From d6be6fedf75b01b34128a7c4d238c97a3f88aba7 Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Fri, 26 Jun 2015 17:04:59 +0200 Subject: [PATCH 01/29] first version of interface to tractography --- nipype/interfaces/mrtrix3/__init__.py | 5 + nipype/interfaces/mrtrix3/tracking.py | 153 ++++++++++++++++++++++++++ nipype/interfaces/setup.py | 1 + 3 files changed, 159 insertions(+) create mode 100644 nipype/interfaces/mrtrix3/__init__.py create mode 100644 nipype/interfaces/mrtrix3/tracking.py diff --git a/nipype/interfaces/mrtrix3/__init__.py b/nipype/interfaces/mrtrix3/__init__.py new file mode 100644 index 0000000000..ecfdf4719b --- /dev/null +++ b/nipype/interfaces/mrtrix3/__init__.py @@ -0,0 +1,5 @@ +# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- +# vi: set ft=python sts=4 ts=4 sw=4 et: +# -*- coding: utf-8 -*- + +from tracking import Tractography diff --git a/nipype/interfaces/mrtrix3/tracking.py b/nipype/interfaces/mrtrix3/tracking.py new file mode 100644 index 0000000000..524530c08a --- /dev/null +++ b/nipype/interfaces/mrtrix3/tracking.py @@ -0,0 +1,153 @@ +# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- +# vi: set ft=python sts=4 ts=4 sw=4 et: +# -*- coding: utf-8 -*- + +""" + Change directory to provide relative paths for doctests + >>> import os + >>> filepath = os.path.dirname(os.path.realpath(__file__ )) + >>> datadir = os.path.realpath(os.path.join(filepath, + ... '../../testing/data')) + >>> os.chdir(datadir) + +""" +import os +import os.path as op + +from nipype.interfaces.base import ( + CommandLineInputSpec, CommandLine, traits, TraitedSpec, File) + +from nipype.utils.filemanip import split_filename +from nipype.interfaces.traits_extension import isdefined + + +class TractographyInputSpec(CommandLineInputSpec): + sph_trait = traits.Tuple(traits.Float, traits.Float, traits.Float, + traits.Float, argstr='%f,%f,%f,%f') + + in_file = File(exists=True, argstr='%s', mandatory=True, position=-2, + desc='input file to be processed') + + out_file = File('tracked.tck', argstr='%s', mandatory=True, position=-1, + usedefault=True, desc='output file containing tracks') + + algorithm = traits.Enum( + 'iFOD2', 'FACT', 'iFOD1', 'Nulldist', 'SD_Stream', 'Tensor_Det', + 'Tensor_Prob', usedefault=True, argstr='-algorithm %s', + desc='tractography algorithm to be used') + + # ROIs processing options + roi_incl = traits.Either( + File(exists=True), sph_trait, argstr='-include %s', + desc=('specify an inclusion region of interest, streamlines must' + ' traverse ALL inclusion regions to be accepted')) + roi_excl = traits.Either( + File(exists=True), sph_trait, argstr='-exclude %s', + desc=('specify an exclusion region of interest, streamlines that' + ' enter ANY exclude region will be discarded')) + roi_mask = traits.Either( + File(exists=True), sph_trait, argstr='-mask %s', + desc=('specify a masking region of interest. If defined,' + 'streamlines exiting the mask will be truncated')) + + # Here streamlines tractography + + # Anatomically-Constrained Tractography options + act_file = File( + exists=True, argstr='-act %s', + desc=('use the Anatomically-Constrained Tractography framework during' + ' tracking; provided image must be in the 5TT ' + '(five - tissue - type) format')) + backtrack = traits.Bool(argstr='-backtrack', + desc='allow tracks to be truncated') + + crop_at_gmwmi = traits.Bool( + argstr='-crop_at_gmwmi', + desc=('crop streamline endpoints more ' + 'precisely as they cross the GM-WM interface')) + + # Tractography seeding options + seed_sphere = traits.Tuple( + traits.Float, traits.Float, traits.Float, traits.Float, + argstr='-seed_sphere %f,%f,%f,%f', desc='spherical seed') + seed_image = File(exists=True, argstr='-seed_image %s', + desc='seed streamlines entirely at random within mask') + seed_rnd_voxel = traits.Enum( + traits.Int(), File(exists=True), + argstr='-seed_random_per_voxel %s %d', + xor=['seed_image', 'seed_grid_voxel'], + desc=('seed a fixed number of streamlines per voxel in a mask ' + 'image; random placement of seeds in each voxel')) + seed_grid_voxel = traits.Enum( + traits.Int(), File(exists=True), + argstr='-seed_grid_per_voxel %s %d', + xor=['seed_image', 'seed_rnd_voxel'], + desc=('seed a fixed number of streamlines per voxel in a mask ' + 'image; place seeds on a 3D mesh grid (grid_size argument ' + 'is per axis; so a grid_size of 3 results in 27 seeds per' + ' voxel)')) + + # missing opts: seed_rejection, seed_gmwmi, seed_dynamic, max_seed_attempts + out_seeds = File( + 'out_seeds.nii.gz', argstr='-output_seeds %s', + desc=('output the seed location of all successful streamlines to' + ' a file')) + + # DW gradient table import options + grad_file = File(exists=True, argstr='-grad %s', + desc='dw gradient scheme (MRTrix format') + grad_fsl = traits.Tuple( + File(exists=True), File(exists=True), argstr='-fslgrad %s %s', + desc='(bvecs, bvals) dw gradient scheme (FSL format') + bval_scale = traits.Enum( + 'yes', 'no', argstr='-bvalue_scaling %s', + desc=('specifies whether the b - values should be scaled by the square' + ' of the corresponding DW gradient norm, as often required for ' + 'multishell or DSI DW acquisition schemes. The default action ' + 'can also be set in the MRtrix config file, under the ' + 'BValueScaling entry. Valid choices are yes / no, true / ' + 'false, 0 / 1 (default: true).')) + + +class TractographyOutputSpec(TraitedSpec): + out_file = File(exists=True, desc='the output filtered tracks') + out_seeds = File(desc=('output the seed location of all successful' + ' streamlines to a file')) + + +class Tractography(CommandLine): + + """ + Performs tractography after selecting the appropriate algorithm + + Example + ------- + + >>> import nipype.interfaces.mrtrix3 as mrt + >>> tk = mrt.Tractography() + >>> tk.inputs.in_file = 'fods.mif' + >>> tk.inputs.roi_mask = 'mask.nii.gz' + >>> tk.inputs.seed_sphere = (80, 100, 70, 10) + >>> tk.cmdline # doctest: +ELLIPSIS + 'tckgen -algorithm iFOD2 -include mask.nii.gz \ +-seed_sphere 80.000000,100.000000,70.000000,10.000000 \ +./fods.nii.gz tracked.tck' + >>> tk.run() # doctest: +SKIP + """ + + _cmd = 'tckgen' + input_spec = TractographyInputSpec + output_spec = TractographyOutputSpec + + def _format_arg(self, name, trait_spec, value): + print name + if 'roi_' in name and isinstance(value, tuple): + value = ['%f' % v for v in value] + return trait_spec.argstr % ','.join(value) + + return super(Tractography, self)._format_arg(name, trait_spec, value) + + def _list_outputs(self): + outputs = self.output_spec().get() + outputs['out_file'] = op.abspath(self.inputs.out_file) + return outputs diff --git a/nipype/interfaces/setup.py b/nipype/interfaces/setup.py index 9d525923ee..ade51ff8a1 100644 --- a/nipype/interfaces/setup.py +++ b/nipype/interfaces/setup.py @@ -19,6 +19,7 @@ def configuration(parent_package='', top_path=None): config.add_subpackage('fsl') config.add_subpackage('mne') config.add_subpackage('mrtrix') + config.add_subpackage('mrtrix3') config.add_subpackage('nipy') config.add_subpackage('spm') config.add_subpackage('slicer') From 55e3f891dd86344f73386cbefd62e54e3cfd3b0b Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Fri, 26 Jun 2015 17:36:29 +0200 Subject: [PATCH 02/29] add estimate response, fix errors in tracking --- nipype/interfaces/mrtrix3/__init__.py | 1 + nipype/interfaces/mrtrix3/preprocess.py | 123 ++++++++++++++++++++++++ nipype/interfaces/mrtrix3/tracking.py | 1 - 3 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 nipype/interfaces/mrtrix3/preprocess.py diff --git a/nipype/interfaces/mrtrix3/__init__.py b/nipype/interfaces/mrtrix3/__init__.py index ecfdf4719b..5240d39f2b 100644 --- a/nipype/interfaces/mrtrix3/__init__.py +++ b/nipype/interfaces/mrtrix3/__init__.py @@ -2,4 +2,5 @@ # vi: set ft=python sts=4 ts=4 sw=4 et: # -*- coding: utf-8 -*- +from preprocess import ResponseSD from tracking import Tractography diff --git a/nipype/interfaces/mrtrix3/preprocess.py b/nipype/interfaces/mrtrix3/preprocess.py new file mode 100644 index 0000000000..64e9ab8388 --- /dev/null +++ b/nipype/interfaces/mrtrix3/preprocess.py @@ -0,0 +1,123 @@ +# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- +# vi: set ft=python sts=4 ts=4 sw=4 et: +# -*- coding: utf-8 -*- + +""" + Change directory to provide relative paths for doctests + >>> import os + >>> filepath = os.path.dirname(os.path.realpath(__file__ )) + >>> datadir = os.path.realpath(os.path.join(filepath, + ... '../../testing/data')) + >>> os.chdir(datadir) + +""" +import os +import os.path as op + +from nipype.interfaces.base import ( + CommandLineInputSpec, CommandLine, traits, TraitedSpec, File) + +from nipype.utils.filemanip import split_filename +from nipype.interfaces.traits_extension import isdefined + + +class ResponseSDInputSpec(CommandLineInputSpec): + in_file = File(exists=True, argstr='%s', mandatory=True, position=-2, + desc='input diffusion weighted images') + + out_file = File( + 'response.txt', argstr='%s', mandatory=True, position=-1, + usedefault=True, desc='output file containing SH coefficients') + + # DW gradient table import options + grad_file = File(exists=True, argstr='-grad %s', + desc='dw gradient scheme (MRTrix format') + grad_fsl = traits.Tuple( + File(exists=True), File(exists=True), argstr='-fslgrad %s %s', + desc='(bvecs, bvals) dw gradient scheme (FSL format') + bval_scale = traits.Enum( + 'yes', 'no', argstr='-bvalue_scaling %s', + desc=('specifies whether the b - values should be scaled by the square' + ' of the corresponding DW gradient norm, as often required for ' + 'multishell or DSI DW acquisition schemes. The default action ' + 'can also be set in the MRtrix config file, under the ' + 'BValueScaling entry. Valid choices are yes / no, true / ' + 'false, 0 / 1 (default: true).')) + + # DW Shell selection options + + shell = traits.List(traits.Float, sep=',', argstr='-shell %f', + desc='specify one or more dw gradient shells') + in_mask = File(exists=True, argstr='-mask %s', + desc='provide initial mask image') + max_sh = traits.Int(8, argstr='-lmax %d', + desc='maximum harmonic degree of response function') + out_sf = File('sf_mask.nii.gz', argstr='-sf %s', + desc='write a mask containing single-fibre voxels') + test_all = traits.Bool(False, argstr='-test_all', + desc='re-test all voxels at every iteration') + + # Optimization + iterations = traits.Int(0, argstr='-max_iters %d', + desc='maximum number of iterations per pass') + max_change = traits.Float( + argstr='-max_change %f', + desc=('maximum percentile change in any response function coefficient;' + ' if no individual coefficient changes by more than this ' + 'fraction, the algorithm is terminated.')) + + # Thresholds + vol_ratio = traits.Float( + .15, argstr='-volume_ratio %f', + desc=('maximal volume ratio between the sum of all other positive' + ' lobes in the voxel and the largest FOD lobe')) + disp_mult = traits.Float( + 1., argstr='-dispersion_multiplier %f', + desc=('dispersion of FOD lobe must not exceed some threshold as ' + 'determined by this multiplier and the FOD dispersion in other ' + 'single-fibre voxels. The threshold is: (mean + (multiplier * ' + '(mean - min))); default = 1.0. Criterion is only applied in ' + 'second pass of RF estimation.')) + int_mult = traits.Float( + 2., argstr='-integral_multiplier %f', + desc=('integral of FOD lobe must not be outside some range as ' + 'determined by this multiplier and FOD lobe integral in other' + ' single-fibre voxels. The range is: (mean +- (multiplier * ' + 'stdev)); default = 2.0. Criterion is only applied in second ' + 'pass of RF estimation.')) + + +class ResponseSDOutputSpec(TraitedSpec): + out_file = File(exists=True, desc='the output response file') + out_sf = File(desc=('mask containing single-fibre voxels')) + + +class ResponseSD(CommandLine): + + """ + Performs tractography after selecting the appropriate algorithm + + Example + ------- + + >>> import nipype.interfaces.mrtrix3 as mrt + >>> resp = mrt.ResponseSD() + >>> resp.inputs.in_file = 'dwi.nii.gz' + >>> resp.inputs.in_mask = 'mask.nii.gz' + >>> resp.inputs.grad_fsl = ('bvecs', 'bvals') + >>> resp.cmdline # doctest: +ELLIPSIS + '' + >>> resp.run() # doctest: +SKIP + """ + + _cmd = 'dwi2response' + input_spec = ResponseSDInputSpec + output_spec = ResponseSDOutputSpec + + def _list_outputs(self): + outputs = self.output_spec().get() + outputs['out_file'] = op.abspath(self.inputs.out_file) + + if isdefined(self.inputs.out_sf): + outputs['out_sf'] = op.abspath(self.inputs.out_sf) + return outputs diff --git a/nipype/interfaces/mrtrix3/tracking.py b/nipype/interfaces/mrtrix3/tracking.py index 524530c08a..3f3fa851fe 100644 --- a/nipype/interfaces/mrtrix3/tracking.py +++ b/nipype/interfaces/mrtrix3/tracking.py @@ -140,7 +140,6 @@ class Tractography(CommandLine): output_spec = TractographyOutputSpec def _format_arg(self, name, trait_spec, value): - print name if 'roi_' in name and isinstance(value, tuple): value = ['%f' % v for v in value] return trait_spec.argstr % ','.join(value) From 814349ef415899bb74e09897bba854dfc15c2baf Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Fri, 26 Jun 2015 17:37:30 +0200 Subject: [PATCH 03/29] add auto tests --- .../mrtrix3/tests/test_auto_ResponseSD.py | 68 +++++++++++++++++ .../mrtrix3/tests/test_auto_Tractography.py | 76 +++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 nipype/interfaces/mrtrix3/tests/test_auto_ResponseSD.py create mode 100644 nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_ResponseSD.py b/nipype/interfaces/mrtrix3/tests/test_auto_ResponseSD.py new file mode 100644 index 0000000000..059df98430 --- /dev/null +++ b/nipype/interfaces/mrtrix3/tests/test_auto_ResponseSD.py @@ -0,0 +1,68 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from nipype.testing import assert_equal +from nipype.interfaces.mrtrix3.preprocess import ResponseSD + +def test_ResponseSD_inputs(): + input_map = dict(args=dict(argstr='%s', + ), + bval_scale=dict(argstr='-bvalue_scaling %s', + ), + disp_mult=dict(argstr='-dispersion_multiplier %f', + ), + environ=dict(nohash=True, + usedefault=True, + ), + grad_file=dict(argstr='-grad %s', + ), + grad_fsl=dict(argstr='-fslgrad %s %s', + ), + ignore_exception=dict(nohash=True, + usedefault=True, + ), + in_file=dict(argstr='%s', + mandatory=True, + position=-2, + ), + in_mask=dict(argstr='-mask %s', + ), + int_mult=dict(argstr='-integral_multiplier %f', + ), + iterations=dict(argstr='-max_iters %d', + ), + max_change=dict(argstr='-max_change %f', + ), + max_sh=dict(argstr='-lmax %d', + ), + out_file=dict(argstr='%s', + mandatory=True, + position=-1, + usedefault=True, + ), + out_sf=dict(argstr='-sf %s', + ), + shell=dict(argstr='-shell %f', + sep=',', + ), + terminal_output=dict(nohash=True, + ), + test_all=dict(argstr='-test_all', + ), + vol_ratio=dict(argstr='-volume_ratio %f', + ), + ) + inputs = ResponseSD.input_spec() + + for key, metadata in input_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(inputs.traits()[key], metakey), value + +def test_ResponseSD_outputs(): + output_map = dict(out_file=dict(), + out_sf=dict(), + ) + outputs = ResponseSD.output_spec() + + for key, metadata in output_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(outputs.traits()[key], metakey), value + diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py b/nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py new file mode 100644 index 0000000000..c53689bfb6 --- /dev/null +++ b/nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py @@ -0,0 +1,76 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from nipype.testing import assert_equal +from nipype.interfaces.mrtrix3.tracking import Tractography + +def test_Tractography_inputs(): + input_map = dict(act_file=dict(argstr='-act %s', + ), + algorithm=dict(argstr='-algorithm %s', + usedefault=True, + ), + args=dict(argstr='%s', + ), + backtrack=dict(argstr='-backtrack', + ), + bval_scale=dict(argstr='-bvalue_scaling %s', + ), + crop_at_gmwmi=dict(argstr='-crop_at_gmwmi', + ), + environ=dict(nohash=True, + usedefault=True, + ), + grad_file=dict(argstr='-grad %s', + ), + grad_fsl=dict(argstr='-fslgrad %s %s', + ), + ignore_exception=dict(nohash=True, + usedefault=True, + ), + in_file=dict(argstr='%s', + mandatory=True, + position=-2, + ), + out_file=dict(argstr='%s', + mandatory=True, + position=-1, + usedefault=True, + ), + out_seeds=dict(argstr='-output_seeds %s', + ), + roi_excl=dict(argstr='-exclude %s', + ), + roi_incl=dict(argstr='-include %s', + ), + roi_mask=dict(argstr='-mask %s', + ), + seed_grid_voxel=dict(argstr='-seed_grid_per_voxel %s %d', + xor=['seed_image', 'seed_rnd_voxel'], + ), + seed_image=dict(argstr='-seed_image %s', + ), + seed_rnd_voxel=dict(argstr='-seed_random_per_voxel %s %d', + xor=['seed_image', 'seed_grid_voxel'], + ), + seed_sphere=dict(argstr='-seed_sphere %f,%f,%f,%f', + ), + sph_trait=dict(argstr='%f,%f,%f,%f', + ), + terminal_output=dict(nohash=True, + ), + ) + inputs = Tractography.input_spec() + + for key, metadata in input_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(inputs.traits()[key], metakey), value + +def test_Tractography_outputs(): + output_map = dict(out_file=dict(), + out_seeds=dict(), + ) + outputs = Tractography.output_spec() + + for key, metadata in output_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(outputs.traits()[key], metakey), value + From 01bea784d8231431d7b47d8aaccdf9576eb2e1a9 Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Fri, 26 Jun 2015 18:09:59 +0200 Subject: [PATCH 04/29] add mesh2pve interface --- nipype/interfaces/mrtrix3/utils.py | 67 ++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 nipype/interfaces/mrtrix3/utils.py diff --git a/nipype/interfaces/mrtrix3/utils.py b/nipype/interfaces/mrtrix3/utils.py new file mode 100644 index 0000000000..2471d97c54 --- /dev/null +++ b/nipype/interfaces/mrtrix3/utils.py @@ -0,0 +1,67 @@ +# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- +# vi: set ft=python sts=4 ts=4 sw=4 et: +# -*- coding: utf-8 -*- + +""" + Change directory to provide relative paths for doctests + >>> import os + >>> filepath = os.path.dirname(os.path.realpath(__file__ )) + >>> datadir = os.path.realpath(os.path.join(filepath, + ... '../../testing/data')) + >>> os.chdir(datadir) + +""" +import os +import os.path as op + +from nipype.interfaces.base import ( + CommandLineInputSpec, CommandLine, traits, TraitedSpec, File) + +from nipype.utils.filemanip import split_filename +from nipype.interfaces.traits_extension import isdefined + + +class Mesh2PVEInputSpec(CommandLineInputSpec): + in_file = File(exists=True, argstr='%s', mandatory=True, position=-3, + desc='input diffusion weighted images') + reference = File(exists=True, argstr='%s', mandatory=True, position=-2, + desc='input diffusion weighted images') + in_first = File( + exists=True, argstr='-first %s', + desc='indicates that the mesh file is provided by FSL FIRST') + + out_file = File( + 'mesh2volume.nii.gz', argstr='%s', mandatory=True, position=-1, + usedefault=True, desc='output file containing SH coefficients') + + +class Mesh2PVEOutputSpec(TraitedSpec): + out_file = File(exists=True, desc='the output response file') + + +class Mesh2PVE(CommandLine): + + """ + Performs tractography after selecting the appropriate algorithm + + Example + ------- + + >>> import nipype.interfaces.mrtrix3 as mrt + >>> m2p = mrt.Mesh2PVE() + >>> m2p.inputs.in_file = 'surf.vtk' + >>> m2p.inputs.reference = 'dwi.nii.gz' + >>> m2p.inputs.in_first = 'T1.nii.gz' + >>> m2p.cmdline # doctest: +ELLIPSIS + 'mesh2pve -first T1.nii.gz surf.vtk dwi.nii.gz mesh2volume.nii.gz' + >>> resp.run() # doctest: +SKIP + """ + + _cmd = 'mesh2pve' + input_spec = Mesh2PVEInputSpec + output_spec = Mesh2PVEOutputSpec + + def _list_outputs(self): + outputs = self.output_spec().get() + outputs['out_file'] = op.abspath(self.inputs.out_file) + return outputs From 1abc676bd9546a1f87d30865b2f5acd8b89654d9 Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Fri, 26 Jun 2015 18:11:36 +0200 Subject: [PATCH 05/29] add missing edit in mrtrix3 --- nipype/interfaces/mrtrix3/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nipype/interfaces/mrtrix3/__init__.py b/nipype/interfaces/mrtrix3/__init__.py index 5240d39f2b..71a76834c1 100644 --- a/nipype/interfaces/mrtrix3/__init__.py +++ b/nipype/interfaces/mrtrix3/__init__.py @@ -2,5 +2,6 @@ # vi: set ft=python sts=4 ts=4 sw=4 et: # -*- coding: utf-8 -*- +from utils import Mesh2PVE from preprocess import ResponseSD from tracking import Tractography From 85452ce62eaf3f585f433c214709ca9236057340 Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Sun, 28 Jun 2015 18:37:55 +0200 Subject: [PATCH 06/29] fix tests --- nipype/interfaces/mrtrix3/preprocess.py | 4 +- .../mrtrix3/tests/test_auto_Mesh2PVE.py | 46 +++++++++++++++++++ nipype/interfaces/mrtrix3/tracking.py | 2 +- nipype/interfaces/mrtrix3/utils.py | 6 +-- nipype/testing/data/fods.mif | 0 5 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 nipype/interfaces/mrtrix3/tests/test_auto_Mesh2PVE.py create mode 100644 nipype/testing/data/fods.mif diff --git a/nipype/interfaces/mrtrix3/preprocess.py b/nipype/interfaces/mrtrix3/preprocess.py index 64e9ab8388..4a3d66ff26 100644 --- a/nipype/interfaces/mrtrix3/preprocess.py +++ b/nipype/interfaces/mrtrix3/preprocess.py @@ -102,11 +102,11 @@ class ResponseSD(CommandLine): >>> import nipype.interfaces.mrtrix3 as mrt >>> resp = mrt.ResponseSD() - >>> resp.inputs.in_file = 'dwi.nii.gz' + >>> resp.inputs.in_file = 'dwi.mif' >>> resp.inputs.in_mask = 'mask.nii.gz' >>> resp.inputs.grad_fsl = ('bvecs', 'bvals') >>> resp.cmdline # doctest: +ELLIPSIS - '' + 'dwi2response -fslgrad bvecs bvals -mask mask.nii.gz dwi.mif' >>> resp.run() # doctest: +SKIP """ diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_Mesh2PVE.py b/nipype/interfaces/mrtrix3/tests/test_auto_Mesh2PVE.py new file mode 100644 index 0000000000..a019f52eb7 --- /dev/null +++ b/nipype/interfaces/mrtrix3/tests/test_auto_Mesh2PVE.py @@ -0,0 +1,46 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from nipype.testing import assert_equal +from nipype.interfaces.mrtrix3.utils import Mesh2PVE + +def test_Mesh2PVE_inputs(): + input_map = dict(args=dict(argstr='%s', + ), + environ=dict(nohash=True, + usedefault=True, + ), + ignore_exception=dict(nohash=True, + usedefault=True, + ), + in_file=dict(argstr='%s', + mandatory=True, + position=-3, + ), + in_first=dict(argstr='-first %s', + ), + out_file=dict(argstr='%s', + mandatory=True, + position=-1, + usedefault=True, + ), + reference=dict(argstr='%s', + mandatory=True, + position=-2, + ), + terminal_output=dict(nohash=True, + ), + ) + inputs = Mesh2PVE.input_spec() + + for key, metadata in input_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(inputs.traits()[key], metakey), value + +def test_Mesh2PVE_outputs(): + output_map = dict(out_file=dict(), + ) + outputs = Mesh2PVE.output_spec() + + for key, metadata in output_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(outputs.traits()[key], metakey), value + diff --git a/nipype/interfaces/mrtrix3/tracking.py b/nipype/interfaces/mrtrix3/tracking.py index 3f3fa851fe..bd29328903 100644 --- a/nipype/interfaces/mrtrix3/tracking.py +++ b/nipype/interfaces/mrtrix3/tracking.py @@ -131,7 +131,7 @@ class Tractography(CommandLine): >>> tk.cmdline # doctest: +ELLIPSIS 'tckgen -algorithm iFOD2 -include mask.nii.gz \ -seed_sphere 80.000000,100.000000,70.000000,10.000000 \ -./fods.nii.gz tracked.tck' +./fods.mif tracked.tck' >>> tk.run() # doctest: +SKIP """ diff --git a/nipype/interfaces/mrtrix3/utils.py b/nipype/interfaces/mrtrix3/utils.py index 2471d97c54..5d4bb2e5d7 100644 --- a/nipype/interfaces/mrtrix3/utils.py +++ b/nipype/interfaces/mrtrix3/utils.py @@ -49,11 +49,11 @@ class Mesh2PVE(CommandLine): >>> import nipype.interfaces.mrtrix3 as mrt >>> m2p = mrt.Mesh2PVE() - >>> m2p.inputs.in_file = 'surf.vtk' - >>> m2p.inputs.reference = 'dwi.nii.gz' + >>> m2p.inputs.in_file = 'surf1.vtk' + >>> m2p.inputs.reference = 'dwi.mif' >>> m2p.inputs.in_first = 'T1.nii.gz' >>> m2p.cmdline # doctest: +ELLIPSIS - 'mesh2pve -first T1.nii.gz surf.vtk dwi.nii.gz mesh2volume.nii.gz' + 'mesh2pve -first T1.nii.gz surf1.vtk dwi.mif mesh2volume.nii.gz' >>> resp.run() # doctest: +SKIP """ diff --git a/nipype/testing/data/fods.mif b/nipype/testing/data/fods.mif new file mode 100644 index 0000000000..e69de29bb2 From 5045a8b1bccf541a698bfa2a573496c897b6be2b Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Sun, 28 Jun 2015 18:51:23 +0200 Subject: [PATCH 07/29] fix tests (2) --- nipype/interfaces/mrtrix3/preprocess.py | 2 +- nipype/interfaces/mrtrix3/tracking.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/nipype/interfaces/mrtrix3/preprocess.py b/nipype/interfaces/mrtrix3/preprocess.py index 4a3d66ff26..def1945790 100644 --- a/nipype/interfaces/mrtrix3/preprocess.py +++ b/nipype/interfaces/mrtrix3/preprocess.py @@ -106,7 +106,7 @@ class ResponseSD(CommandLine): >>> resp.inputs.in_mask = 'mask.nii.gz' >>> resp.inputs.grad_fsl = ('bvecs', 'bvals') >>> resp.cmdline # doctest: +ELLIPSIS - 'dwi2response -fslgrad bvecs bvals -mask mask.nii.gz dwi.mif' + 'dwi2response -fslgrad bvecs bvals -mask mask.nii.gz dwi.mif response.txt' >>> resp.run() # doctest: +SKIP """ diff --git a/nipype/interfaces/mrtrix3/tracking.py b/nipype/interfaces/mrtrix3/tracking.py index bd29328903..3955c12f6d 100644 --- a/nipype/interfaces/mrtrix3/tracking.py +++ b/nipype/interfaces/mrtrix3/tracking.py @@ -129,9 +129,8 @@ class Tractography(CommandLine): >>> tk.inputs.roi_mask = 'mask.nii.gz' >>> tk.inputs.seed_sphere = (80, 100, 70, 10) >>> tk.cmdline # doctest: +ELLIPSIS - 'tckgen -algorithm iFOD2 -include mask.nii.gz \ --seed_sphere 80.000000,100.000000,70.000000,10.000000 \ -./fods.mif tracked.tck' + 'tckgen -algorithm iFOD2 -mask mask.nii.gz -seed_sphere \ +80.000000,100.000000,70.000000,10.000000 fods.mif tracked.tck' >>> tk.run() # doctest: +SKIP """ From 7647d7305a78d1f643b29328e6b96aec4aeccd20 Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Sun, 28 Jun 2015 19:16:13 +0200 Subject: [PATCH 08/29] add interface to act_anat_prepare_fsl --- nipype/interfaces/mrtrix3/preprocess.py | 39 ++++++++++++++++++ .../mrtrix3/tests/test_auto_ACTPrepareFSL.py | 40 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 nipype/interfaces/mrtrix3/tests/test_auto_ACTPrepareFSL.py diff --git a/nipype/interfaces/mrtrix3/preprocess.py b/nipype/interfaces/mrtrix3/preprocess.py index def1945790..050ee3cf20 100644 --- a/nipype/interfaces/mrtrix3/preprocess.py +++ b/nipype/interfaces/mrtrix3/preprocess.py @@ -121,3 +121,42 @@ def _list_outputs(self): if isdefined(self.inputs.out_sf): outputs['out_sf'] = op.abspath(self.inputs.out_sf) return outputs + + +class ACTPrepareFSLInputSpec(CommandLineInputSpec): + in_file = File(exists=True, argstr='%s', mandatory=True, position=-2, + desc='input anatomical image') + + out_file = File( + 'act_5tt.mif', argstr='%s', mandatory=True, position=-1, + usedefault=True, desc='output file after processing') + + +class ACTPrepareFSLOutputSpec(TraitedSpec): + out_file = File(exists=True, desc='the output response file') + + +class ACTPrepareFSL(CommandLine): + + """ + Performs tractography after selecting the appropriate algorithm + + Example + ------- + + >>> import nipype.interfaces.mrtrix3 as mrt + >>> resp = mrt.ACTPrepareFSL() + >>> resp.inputs.in_file = 'T1.nii.gz' + >>> resp.cmdline # doctest: +ELLIPSIS + 'act_anat_prepare_fsl T1.nii.gz act_5tt.mif' + >>> resp.run() # doctest: +SKIP + """ + + _cmd = 'act_anat_prepare_fsl' + input_spec = ACTPrepareFSLInputSpec + output_spec = ACTPrepareFSLOutputSpec + + def _list_outputs(self): + outputs = self.output_spec().get() + outputs['out_file'] = op.abspath(self.inputs.out_file) + return outputs \ No newline at end of file diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_ACTPrepareFSL.py b/nipype/interfaces/mrtrix3/tests/test_auto_ACTPrepareFSL.py new file mode 100644 index 0000000000..7a8c4a54a0 --- /dev/null +++ b/nipype/interfaces/mrtrix3/tests/test_auto_ACTPrepareFSL.py @@ -0,0 +1,40 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from nipype.testing import assert_equal +from nipype.interfaces.mrtrix3.preprocess import ACTPrepareFSL + +def test_ACTPrepareFSL_inputs(): + input_map = dict(args=dict(argstr='%s', + ), + environ=dict(nohash=True, + usedefault=True, + ), + ignore_exception=dict(nohash=True, + usedefault=True, + ), + in_file=dict(argstr='%s', + mandatory=True, + position=-2, + ), + out_file=dict(argstr='%s', + mandatory=True, + position=-1, + usedefault=True, + ), + terminal_output=dict(nohash=True, + ), + ) + inputs = ACTPrepareFSL.input_spec() + + for key, metadata in input_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(inputs.traits()[key], metakey), value + +def test_ACTPrepareFSL_outputs(): + output_map = dict(out_file=dict(), + ) + outputs = ACTPrepareFSL.output_spec() + + for key, metadata in output_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(outputs.traits()[key], metakey), value + From 7892cbc5476da29a0029428b6ea7269dc723d6c4 Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Sun, 28 Jun 2015 19:28:24 +0200 Subject: [PATCH 09/29] fix tests new interface. Update CHANGES --- CHANGES | 1 + nipype/interfaces/mrtrix3/__init__.py | 2 +- nipype/interfaces/mrtrix3/preprocess.py | 8 ++++---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index c037112f69..e6bff7b9c5 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,7 @@ Next release ============ +* ENH: New interfaces for MRTrix3 (https://github.com/nipy/nipype/pull/1126) * FIX: Enable absolute path definitions in DCMStack (https://github.com/nipy/nipype/pull/1089, replaced by https://github.com/nipy/nipype/pull/1093) * ENH: New mesh.MeshWarpMaths to operate on surface-defined warpings diff --git a/nipype/interfaces/mrtrix3/__init__.py b/nipype/interfaces/mrtrix3/__init__.py index 71a76834c1..e6c8cd05b6 100644 --- a/nipype/interfaces/mrtrix3/__init__.py +++ b/nipype/interfaces/mrtrix3/__init__.py @@ -3,5 +3,5 @@ # -*- coding: utf-8 -*- from utils import Mesh2PVE -from preprocess import ResponseSD +from preprocess import ResponseSD, ACTPrepareFSL from tracking import Tractography diff --git a/nipype/interfaces/mrtrix3/preprocess.py b/nipype/interfaces/mrtrix3/preprocess.py index 050ee3cf20..12924f802f 100644 --- a/nipype/interfaces/mrtrix3/preprocess.py +++ b/nipype/interfaces/mrtrix3/preprocess.py @@ -145,11 +145,11 @@ class ACTPrepareFSL(CommandLine): ------- >>> import nipype.interfaces.mrtrix3 as mrt - >>> resp = mrt.ACTPrepareFSL() - >>> resp.inputs.in_file = 'T1.nii.gz' - >>> resp.cmdline # doctest: +ELLIPSIS + >>> prep = mrt.ACTPrepareFSL() + >>> prep.inputs.in_file = 'T1.nii.gz' + >>> prep.cmdline # doctest: +ELLIPSIS 'act_anat_prepare_fsl T1.nii.gz act_5tt.mif' - >>> resp.run() # doctest: +SKIP + >>> prep.run() # doctest: +SKIP """ _cmd = 'act_anat_prepare_fsl' From 6d4c6ad3756c3fbd264b5734132fff445bde8314 Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Mon, 29 Jun 2015 08:30:37 +0200 Subject: [PATCH 10/29] fix docstrings --- nipype/interfaces/mrtrix3/preprocess.py | 14 +++++++++--- nipype/interfaces/mrtrix3/tracking.py | 30 ++++++++++++++++++++++++- nipype/interfaces/mrtrix3/utils.py | 3 ++- 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/nipype/interfaces/mrtrix3/preprocess.py b/nipype/interfaces/mrtrix3/preprocess.py index 12924f802f..14dfe241d0 100644 --- a/nipype/interfaces/mrtrix3/preprocess.py +++ b/nipype/interfaces/mrtrix3/preprocess.py @@ -95,7 +95,14 @@ class ResponseSDOutputSpec(TraitedSpec): class ResponseSD(CommandLine): """ - Performs tractography after selecting the appropriate algorithm + Generate an appropriate response function from the image data for + spherical deconvolution. + + .. [1] Tax, C. M.; Jeurissen, B.; Vos, S. B.; Viergever, M. A. and + Leemans, A., Recursive calibration of the fiber response function + for spherical deconvolution of diffusion MRI data. NeuroImage, + 2014, 86, 67-80 + Example ------- @@ -139,7 +146,8 @@ class ACTPrepareFSLOutputSpec(TraitedSpec): class ACTPrepareFSL(CommandLine): """ - Performs tractography after selecting the appropriate algorithm + Generate anatomical information necessary for Anatomically + Constrained Tractography (ACT). Example ------- @@ -159,4 +167,4 @@ class ACTPrepareFSL(CommandLine): def _list_outputs(self): outputs = self.output_spec().get() outputs['out_file'] = op.abspath(self.inputs.out_file) - return outputs \ No newline at end of file + return outputs diff --git a/nipype/interfaces/mrtrix3/tracking.py b/nipype/interfaces/mrtrix3/tracking.py index 3955c12f6d..19721ac61e 100644 --- a/nipype/interfaces/mrtrix3/tracking.py +++ b/nipype/interfaces/mrtrix3/tracking.py @@ -118,7 +118,35 @@ class TractographyOutputSpec(TraitedSpec): class Tractography(CommandLine): """ - Performs tractography after selecting the appropriate algorithm + Performs streamlines tractography after selecting the appropriate + algorithm. + + .. [FACT] Mori, S.; Crain, B. J.; Chacko, V. P. & van Zijl, + P. C. M. Three-dimensional tracking of axonal projections in the + brain by magnetic resonance imaging. Annals of Neurology, 1999, + 45, 265-269 + + .. [iFOD1] Tournier, J.-D.; Calamante, F. & Connelly, A. MRtrix: + Diffusion tractography in crossing fiber regions. Int. J. Imaging + Syst. Technol., 2012, 22, 53-66 + + .. [iFOD2] Tournier, J.-D.; Calamante, F. & Connelly, A. Improved + probabilistic streamlines tractography by 2nd order integration + over fibre orientation distributions. Proceedings of the + International Society for Magnetic Resonance in Medicine, 2010, 1670 + + .. [Nulldist] Morris, D. M.; Embleton, K. V. & Parker, G. J. + Probabilistic fibre tracking: Differentiation of connections from + chance events. NeuroImage, 2008, 42, 1329-1339 + + .. [Tensor_Det] Basser, P. J.; Pajevic, S.; Pierpaoli, C.; Duda, J. + and Aldroubi, A. In vivo fiber tractography using DT-MRI data. + Magnetic Resonance in Medicine, 2000, 44, 625-632 + + .. [Tensor_Prob] Jones, D. Tractography Gone Wild: Probabilistic Fibre + Tracking Using the Wild Bootstrap With Diffusion Tensor MRI. IEEE + Transactions on Medical Imaging, 2008, 27, 1268-1274 + Example ------- diff --git a/nipype/interfaces/mrtrix3/utils.py b/nipype/interfaces/mrtrix3/utils.py index 5d4bb2e5d7..11f5c650a4 100644 --- a/nipype/interfaces/mrtrix3/utils.py +++ b/nipype/interfaces/mrtrix3/utils.py @@ -42,7 +42,8 @@ class Mesh2PVEOutputSpec(TraitedSpec): class Mesh2PVE(CommandLine): """ - Performs tractography after selecting the appropriate algorithm + Convert a mesh surface to a partial volume estimation image + Example ------- From a5c6164129cb22c150b2012f30f4cf56a3782989 Mon Sep 17 00:00:00 2001 From: oesteban Date: Mon, 29 Jun 2015 19:57:02 +0200 Subject: [PATCH 11/29] add options to tracking interface --- .../mrtrix3/tests/test_auto_Tractography.py | 43 ++++++++ nipype/interfaces/mrtrix3/tracking.py | 101 ++++++++++++++++-- 2 files changed, 137 insertions(+), 7 deletions(-) diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py b/nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py index c53689bfb6..a8fa1c49fa 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py @@ -8,6 +8,8 @@ def test_Tractography_inputs(): algorithm=dict(argstr='-algorithm %s', usedefault=True, ), + angle=dict(argstr='-angle %f', + ), args=dict(argstr='%s', ), backtrack=dict(argstr='-backtrack', @@ -16,6 +18,12 @@ def test_Tractography_inputs(): ), crop_at_gmwmi=dict(argstr='-crop_at_gmwmi', ), + cutoff=dict(argstr='-cutoff %f', + ), + cutoff_init=dict(argstr='-initcutoff %f', + ), + downsample=dict(argstr='-downsample %f', + ), environ=dict(nohash=True, usedefault=True, ), @@ -30,6 +38,24 @@ def test_Tractography_inputs(): mandatory=True, position=-2, ), + init_dir=dict(argstr='-initdirection %f,%f,%f', + ), + max_length=dict(argstr='-maxlength %f', + ), + max_seed_attempts=dict(argstr='-max_seed_attempts %d', + ), + max_tracks=dict(argstr='-maxnum %d', + ), + min_length=dict(argstr='-minlength %f', + ), + n_samples=dict(argstr='-samples %d', + ), + n_tracks=dict(argstr='-number %d', + ), + n_trials=dict(argstr='-trials %d', + ), + noprecompt=dict(argstr='-noprecomputed', + ), out_file=dict(argstr='%s', mandatory=True, position=-1, @@ -37,17 +63,26 @@ def test_Tractography_inputs(): ), out_seeds=dict(argstr='-output_seeds %s', ), + power=dict(argstr='-power %d', + ), roi_excl=dict(argstr='-exclude %s', ), roi_incl=dict(argstr='-include %s', ), roi_mask=dict(argstr='-mask %s', ), + seed_dynamic=dict(argstr='-seed_dynamic %s', + ), + seed_gmwmi=dict(argstr='-seed_gmwmi %s', + requires=['act_file'], + ), seed_grid_voxel=dict(argstr='-seed_grid_per_voxel %s %d', xor=['seed_image', 'seed_rnd_voxel'], ), seed_image=dict(argstr='-seed_image %s', ), + seed_rejection=dict(argstr='-seed_rejection %s', + ), seed_rnd_voxel=dict(argstr='-seed_random_per_voxel %s %d', xor=['seed_image', 'seed_grid_voxel'], ), @@ -55,8 +90,16 @@ def test_Tractography_inputs(): ), sph_trait=dict(argstr='%f,%f,%f,%f', ), + step_size=dict(argstr='-step %f', + ), + stop=dict(argstr='-stop', + ), terminal_output=dict(nohash=True, ), + unidirectional=dict(argstr='-unidirectional', + ), + use_rk4=dict(argstr='-rk4', + ), ) inputs = Tractography.input_spec() diff --git a/nipype/interfaces/mrtrix3/tracking.py b/nipype/interfaces/mrtrix3/tracking.py index 19721ac61e..4fac45c5aa 100644 --- a/nipype/interfaces/mrtrix3/tracking.py +++ b/nipype/interfaces/mrtrix3/tracking.py @@ -50,7 +50,77 @@ class TractographyInputSpec(CommandLineInputSpec): desc=('specify a masking region of interest. If defined,' 'streamlines exiting the mask will be truncated')) - # Here streamlines tractography + # Streamlines tractography options + step_size = traits.Float( + argstr='-step %f', + desc=('set the step size of the algorithm in mm (default is 0.1' + ' x voxelsize; for iFOD2: 0.5 x voxelsize)')) + angle = traits.Float( + argstr='-angle %f', + desc=('set the maximum angle between successive steps (default ' + 'is 90deg x stepsize / voxelsize)')) + n_tracks = traits.Int( + argstr='-number %d', + desc=('set the desired number of tracks. The program will continue' + ' to generate tracks until this number of tracks have been ' + 'selected and written to the output file')) + max_tracks = traits.Int( + argstr='-maxnum %d', + desc=('set the maximum number of tracks to generate. The program ' + 'will not generate more tracks than this number, even if ' + 'the desired number of tracks hasn\'t yet been reached ' + '(default is 100 x number)')) + max_length = traits.Float( + argstr='-maxlength %f', + desc=('set the maximum length of any track in mm (default is ' + '100 x voxelsize)')) + min_length = traits.Float( + argstr='-minlength %f', + desc=('set the minimum length of any track in mm (default is ' + '5 x voxelsize)')) + cutoff = traits.Float( + argstr='-cutoff %f', + desc=('set the FA or FOD amplitude cutoff for terminating ' + 'tracks (default is 0.1)')) + cutoff_init = traits.Float( + argstr='-initcutoff %f', + desc=('set the minimum FA or FOD amplitude for initiating ' + 'tracks (default is the same as the normal cutoff)')) + n_trials = traits.Int( + argstr='-trials %d', + desc=('set the maximum number of sampling trials at each point' + ' (only used for probabilistic tracking)')) + unidirectional = traits.Bool( + argstr='-unidirectional', + desc=('track from the seed point in one direction only ' + '(default is to track in both directions)')) + init_dir = traits.Tuple( + traits.Float, traits.Float, traits.Float, + argstr='-initdirection %f,%f,%f', + desc=('specify an initial direction for the tracking (this ' + 'should be supplied as a vector of 3 comma-separated values')) + noprecompt = traits.Bool( + argstr='-noprecomputed', + desc=('do NOT pre-compute legendre polynomial values. Warning: this ' + 'will slow down the algorithm by a factor of approximately 4')) + power = traits.Int( + argstr='-power %d', + desc=('raise the FOD to the power specified (default is 1/nsamples)')) + n_samples = traits.Int( + 4, argstr='-samples %d', + desc=('set the number of FOD samples to take per step for the 2nd ' + 'order (iFOD2) method')) + use_rk4 = traits.Bool( + argstr='-rk4', + desc=('use 4th-order Runge-Kutta integration (slower, but eliminates' + ' curvature overshoot in 1st-order deterministic methods)')) + stop = traits.Bool( + argstr='-stop', + desc=('stop propagating a streamline once it has traversed all ' + 'include regions')) + downsample = traits.Float( + argstr='-downsample %f', + desc=('downsample the generated streamlines to reduce output file size')) # Anatomically-Constrained Tractography options act_file = File( @@ -72,22 +142,39 @@ class TractographyInputSpec(CommandLineInputSpec): argstr='-seed_sphere %f,%f,%f,%f', desc='spherical seed') seed_image = File(exists=True, argstr='-seed_image %s', desc='seed streamlines entirely at random within mask') - seed_rnd_voxel = traits.Enum( - traits.Int(), File(exists=True), + seed_rnd_voxel = traits.Tuple( + File(exists=True), traits.Int(), argstr='-seed_random_per_voxel %s %d', xor=['seed_image', 'seed_grid_voxel'], desc=('seed a fixed number of streamlines per voxel in a mask ' 'image; random placement of seeds in each voxel')) - seed_grid_voxel = traits.Enum( - traits.Int(), File(exists=True), + seed_grid_voxel = traits.Tuple( + File(exists=True), traits.Int(), argstr='-seed_grid_per_voxel %s %d', xor=['seed_image', 'seed_rnd_voxel'], desc=('seed a fixed number of streamlines per voxel in a mask ' 'image; place seeds on a 3D mesh grid (grid_size argument ' 'is per axis; so a grid_size of 3 results in 27 seeds per' ' voxel)')) - - # missing opts: seed_rejection, seed_gmwmi, seed_dynamic, max_seed_attempts + seed_rejection = File( + exists=True, argstr='-seed_rejection %s', + desc=('seed from an image using rejection sampling (higher ' + 'values = more probable to seed from')) + seed_gmwmi = File( + exists=True, argstr='-seed_gmwmi %s', requires=['act_file'], + desc=('seed from the grey matter - white matter interface (only ' + 'valid if using ACT framework)')) + seed_dynamic = File( + exists=True, argstr='-seed_dynamic %s', + desc=('determine seed points dynamically using the SIFT model ' + '(must not provide any other seeding mechanism). Note that' + ' while this seeding mechanism improves the distribution of' + ' reconstructed streamlines density, it should NOT be used ' + 'as a substitute for the SIFT method itself.')) + max_seed_attempts = traits.Int(argstr='-max_seed_attempts %d', + desc=('set the maximum number of times that the tracking ' + 'algorithm should attempt to find an appropriate tracking' + ' direction from a given seed point')) out_seeds = File( 'out_seeds.nii.gz', argstr='-output_seeds %s', desc=('output the seed location of all successful streamlines to' From 4ddbd057853370cb62b96fbc051dd0bd2e36fd85 Mon Sep 17 00:00:00 2001 From: oesteban Date: Tue, 30 Jun 2015 11:38:41 +0200 Subject: [PATCH 12/29] Add 5ttgen interface --- nipype/interfaces/mrtrix3/__init__.py | 2 +- .../mrtrix3/tests/test_auto_Generate5tt.py | 43 +++++++++++++++ nipype/interfaces/mrtrix3/tracking.py | 2 +- nipype/interfaces/mrtrix3/utils.py | 52 ++++++++++++++++++- nipype/testing/data/first_merged.nii.gz | 0 5 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 nipype/interfaces/mrtrix3/tests/test_auto_Generate5tt.py create mode 100644 nipype/testing/data/first_merged.nii.gz diff --git a/nipype/interfaces/mrtrix3/__init__.py b/nipype/interfaces/mrtrix3/__init__.py index e6c8cd05b6..b1d36b7f18 100644 --- a/nipype/interfaces/mrtrix3/__init__.py +++ b/nipype/interfaces/mrtrix3/__init__.py @@ -2,6 +2,6 @@ # vi: set ft=python sts=4 ts=4 sw=4 et: # -*- coding: utf-8 -*- -from utils import Mesh2PVE +from utils import Mesh2PVE, Generate5tt from preprocess import ResponseSD, ACTPrepareFSL from tracking import Tractography diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_Generate5tt.py b/nipype/interfaces/mrtrix3/tests/test_auto_Generate5tt.py new file mode 100644 index 0000000000..a6e4e76989 --- /dev/null +++ b/nipype/interfaces/mrtrix3/tests/test_auto_Generate5tt.py @@ -0,0 +1,43 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from nipype.testing import assert_equal +from nipype.interfaces.mrtrix3.utils import Generate5tt + +def test_Generate5tt_inputs(): + input_map = dict(args=dict(argstr='%s', + ), + environ=dict(nohash=True, + usedefault=True, + ), + ignore_exception=dict(nohash=True, + usedefault=True, + ), + in_fast=dict(argstr='%s', + mandatory=True, + position=-3, + ), + in_first=dict(argstr='%s', + position=-2, + ), + out_file=dict(argstr='%s', + mandatory=True, + position=-1, + usedefault=True, + ), + terminal_output=dict(nohash=True, + ), + ) + inputs = Generate5tt.input_spec() + + for key, metadata in input_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(inputs.traits()[key], metakey), value + +def test_Generate5tt_outputs(): + output_map = dict(out_file=dict(), + ) + outputs = Generate5tt.output_spec() + + for key, metadata in output_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(outputs.traits()[key], metakey), value + diff --git a/nipype/interfaces/mrtrix3/tracking.py b/nipype/interfaces/mrtrix3/tracking.py index 4fac45c5aa..ab3dc494e9 100644 --- a/nipype/interfaces/mrtrix3/tracking.py +++ b/nipype/interfaces/mrtrix3/tracking.py @@ -95,7 +95,7 @@ class TractographyInputSpec(CommandLineInputSpec): desc=('track from the seed point in one direction only ' '(default is to track in both directions)')) init_dir = traits.Tuple( - traits.Float, traits.Float, traits.Float, + traits.Float, traits.Float, traits.Float, argstr='-initdirection %f,%f,%f', desc=('specify an initial direction for the tracking (this ' 'should be supplied as a vector of 3 comma-separated values')) diff --git a/nipype/interfaces/mrtrix3/utils.py b/nipype/interfaces/mrtrix3/utils.py index 11f5c650a4..56893d0ab7 100644 --- a/nipype/interfaces/mrtrix3/utils.py +++ b/nipype/interfaces/mrtrix3/utils.py @@ -15,7 +15,8 @@ import os.path as op from nipype.interfaces.base import ( - CommandLineInputSpec, CommandLine, traits, TraitedSpec, File) + CommandLineInputSpec, CommandLine, traits, TraitedSpec, File, + InputMultiPath) from nipype.utils.filemanip import split_filename from nipype.interfaces.traits_extension import isdefined @@ -55,7 +56,7 @@ class Mesh2PVE(CommandLine): >>> m2p.inputs.in_first = 'T1.nii.gz' >>> m2p.cmdline # doctest: +ELLIPSIS 'mesh2pve -first T1.nii.gz surf1.vtk dwi.mif mesh2volume.nii.gz' - >>> resp.run() # doctest: +SKIP + >>> m2p.run() # doctest: +SKIP """ _cmd = 'mesh2pve' @@ -66,3 +67,50 @@ def _list_outputs(self): outputs = self.output_spec().get() outputs['out_file'] = op.abspath(self.inputs.out_file) return outputs + + +class Generate5ttInputSpec(CommandLineInputSpec): + in_fast = InputMultiPath( + File(exists=True), argstr='%s', mandatory=True, position=-3, + desc='list of PVE images from FAST') + in_first = File( + exists=True, argstr='%s', position=-2, + desc='combined segmentation file from FIRST') + out_file = File( + 'act-5tt.mif', argstr='%s', mandatory=True, position=-1, + usedefault=True, desc='name of output file') + + +class Generate5ttOutputSpec(TraitedSpec): + out_file = File(exists=True, desc='segmentation for ACT in 5tt format') + + +class Generate5tt(CommandLine): + + """ + Concatenate segmentation results from FSL FAST and FIRST into the 5TT + format required for ACT + + + Example + ------- + + >>> import nipype.interfaces.mrtrix3 as mrt + >>> seg = mrt.Generate5tt() + >>> seg.inputs.in_fast = ['tpm_00.nii.gz', + ... 'tpm_01.nii.gz', 'tpm_02.nii.gz'] + >>> seg.inputs.in_first = 'first_merged.nii.gz' + >>> seg.cmdline # doctest: +ELLIPSIS + '5ttgen tpm_00.nii.gz tpm_01.nii.gz tpm_02.nii.gz first_merged.nii.gz\ + act-5tt.mif' + >>> seg.run() # doctest: +SKIP + """ + + _cmd = '5ttgen' + input_spec = Generate5ttInputSpec + output_spec = Generate5ttOutputSpec + + def _list_outputs(self): + outputs = self.output_spec().get() + outputs['out_file'] = op.abspath(self.inputs.out_file) + return outputs diff --git a/nipype/testing/data/first_merged.nii.gz b/nipype/testing/data/first_merged.nii.gz new file mode 100644 index 0000000000..e69de29bb2 From 0f45bc9a72ea3ca43ae797dc49986a44d4a2229e Mon Sep 17 00:00:00 2001 From: oesteban Date: Tue, 30 Jun 2015 19:04:35 +0200 Subject: [PATCH 13/29] Add dwi2tensor and dwi2fod --- nipype/interfaces/mrtrix3/__init__.py | 1 + nipype/interfaces/mrtrix3/reconst.py | 218 ++++++++++++++++++ .../mrtrix3/tests/test_auto_EstimateFOD.py | 67 ++++++ .../mrtrix3/tests/test_auto_FitTensor.py | 52 +++++ 4 files changed, 338 insertions(+) create mode 100644 nipype/interfaces/mrtrix3/reconst.py create mode 100644 nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py create mode 100644 nipype/interfaces/mrtrix3/tests/test_auto_FitTensor.py diff --git a/nipype/interfaces/mrtrix3/__init__.py b/nipype/interfaces/mrtrix3/__init__.py index b1d36b7f18..2fe363c48c 100644 --- a/nipype/interfaces/mrtrix3/__init__.py +++ b/nipype/interfaces/mrtrix3/__init__.py @@ -5,3 +5,4 @@ from utils import Mesh2PVE, Generate5tt from preprocess import ResponseSD, ACTPrepareFSL from tracking import Tractography +from reconst import FitTensor, EstimateFOD diff --git a/nipype/interfaces/mrtrix3/reconst.py b/nipype/interfaces/mrtrix3/reconst.py new file mode 100644 index 0000000000..f5a8506376 --- /dev/null +++ b/nipype/interfaces/mrtrix3/reconst.py @@ -0,0 +1,218 @@ +# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- +# vi: set ft=python sts=4 ts=4 sw=4 et: +# -*- coding: utf-8 -*- + +""" + Change directory to provide relative paths for doctests + >>> import os + >>> filepath = os.path.dirname(os.path.realpath(__file__ )) + >>> datadir = os.path.realpath(os.path.join(filepath, + ... '../../testing/data')) + >>> os.chdir(datadir) + +""" +import os +import os.path as op + +from nipype.interfaces.base import ( + CommandLineInputSpec, CommandLine, traits, TraitedSpec, File, + InputMultiPath) + +from nipype.utils.filemanip import split_filename +from nipype.interfaces.traits_extension import isdefined + +class FitTensorInputSpec(CommandLineInputSpec): + in_file = File(exists=True, argstr='%s', mandatory=True, position=-2, + desc='input diffusion weighted images') + out_file = File( + 'dti.mif', argstr='%s', mandatory=True, position=-1, + usedefault=True, desc='the output diffusion tensor image') + + # General options + in_mask = File(exists=True, argstr='-mask %s', + desc=('only perform computation within the specified binary ' + 'brain mask image')) + method = traits.Enum( + 'nonlinear', 'loglinear', 'sech', 'rician', argstr='-method %s', + desc=('select method used to perform the fitting')) + reg_term = traits.Float( + 5.e3, argstr='-regularisation %f', + desc=('specify the strength of the regularisation term on the magnitude ' + 'of the tensor elements (default = 5000). This only applies to the ' + 'non-linear methods')) + + + # DW gradient table import options + grad_file = File(exists=True, argstr='-grad %s', + desc='dw gradient scheme (MRTrix format') + grad_fsl = traits.Tuple( + File(exists=True), File(exists=True), argstr='-fslgrad %s %s', + desc='(bvecs, bvals) dw gradient scheme (FSL format') + bval_scale = traits.Enum( + 'yes', 'no', argstr='-bvalue_scaling %s', + desc=('specifies whether the b - values should be scaled by the square' + ' of the corresponding DW gradient norm, as often required for ' + 'multishell or DSI DW acquisition schemes. The default action ' + 'can also be set in the MRtrix config file, under the ' + 'BValueScaling entry. Valid choices are yes / no, true / ' + 'false, 0 / 1 (default: true).')) + + +class FitTensorOutputSpec(TraitedSpec): + out_file = File(exists=True, desc='the output DTI file') + + +class FitTensor(CommandLine): + + """ + Convert diffusion-weighted images to tensor images + + + Example + ------- + + >>> import nipype.interfaces.mrtrix3 as mrt + >>> tsr = mrt.FitTensor() + >>> tsr.inputs.in_file = 'dwi.mif' + >>> tsr.inputs.in_mask = 'mask.nii.gz' + >>> tsr.inputs.grad_fsl = ('bvecs', 'bvals') + >>> tsr.cmdline # doctest: +ELLIPSIS + 'dwi2tensor -fslgrad bvecs bvals -mask mask.nii.gz dwi.mif dti.mif' + >>> tsr.run() # doctest: +SKIP + """ + + _cmd = 'dwi2tensor' + input_spec = FitTensorInputSpec + output_spec = FitTensorOutputSpec + + def _list_outputs(self): + outputs = self.output_spec().get() + outputs['out_file'] = op.abspath(self.inputs.out_file) + return outputs + + +class EstimateFODInputSpec(CommandLineInputSpec): + in_file = File(exists=True, argstr='%s', mandatory=True, position=-3, + desc='input diffusion weighted images') + response = File( + exists=True, argstr='%s', mandatory=True, position=-2, + desc=('a text file containing the diffusion-weighted signal response ' + 'function coefficients for a single fibre population')) + out_file = File( + 'fods.mif', argstr='%s', mandatory=True, position=-1, + usedefault=True, desc='the output spherical harmonics coefficients image') + + # DW gradient table import options + grad_file = File(exists=True, argstr='-grad %s', + desc='dw gradient scheme (MRTrix format') + grad_fsl = traits.Tuple( + File(exists=True), File(exists=True), argstr='-fslgrad %s %s', + desc='(bvecs, bvals) dw gradient scheme (FSL format') + bval_scale = traits.Enum( + 'yes', 'no', argstr='-bvalue_scaling %s', + desc=('specifies whether the b - values should be scaled by the square' + ' of the corresponding DW gradient norm, as often required for ' + 'multishell or DSI DW acquisition schemes. The default action ' + 'can also be set in the MRtrix config file, under the ' + 'BValueScaling entry. Valid choices are yes / no, true / ' + 'false, 0 / 1 (default: true).')) + + # DW Shell selection options + shell = traits.List(traits.Float, sep=',', argstr='-shell %f', + desc='specify one or more dw gradient shells') + + # Spherical deconvolution options + max_sh = traits.Int(8, argstr='-lmax %d', + desc='maximum harmonic degree of response function') + in_mask = File(exists=True, argstr='-mask %s', + desc='provide initial mask image') + in_dirs = File( + exists=True, argstr='-directions %s', + desc=('specify the directions over which to apply the non-negativity ' + 'constraint (by default, the built-in 300 direction set is used). ' + 'These should be supplied as a text file containing the [ az el ] ' + 'pairs for the directions.')) + sh_filter = File( + exists=True, argstr='-filter %s', + desc=('the linear frequency filtering parameters used for the initial ' + 'linear spherical deconvolution step (default = [ 1 1 1 0 0 ]). ' + 'These should be supplied as a text file containing the filtering ' + 'coefficients for each even harmonic order.')) + + neg_lambda = traits.Float( + 1.0, argstr='-neg_lambda %f', + desc=('the regularisation parameter lambda that controls the strength of ' + 'the non-negativity constraint')) + thres = traits.Float( + 0.0, argstr='-threshold %f', + desc=('the threshold below which the amplitude of the FOD is assumed to be ' + 'zero, expressed as an absolute amplitude')) + + n_iter = traits.Int(50, argstr='-niter %d', desc=('the maximum number of iterat' + 'ions to perform for each voxel')) + + +class EstimateFODOutputSpec(TraitedSpec): + out_file = File(exists=True, desc='the output response file') + + +class EstimateFOD(CommandLine): + + """ + Convert diffusion-weighted images to tensor images + + Note that this program makes use of implied symmetries in the diffusion + profile. First, the fact the signal attenuation profile is real implies + that it has conjugate symmetry, i.e. Y(l,-m) = Y(l,m)* (where * denotes + the complex conjugate). Second, the diffusion profile should be + antipodally symmetric (i.e. S(x) = S(-x)), implying that all odd l + components should be zero. Therefore, this program only computes the even + elements. + + Note that the spherical harmonics equations used here differ slightly from + those conventionally used, in that the (-1)^m factor has been omitted. + This should be taken into account in all subsequent calculations. + The spherical harmonic coefficients are stored as follows. First, since + the signal attenuation profile is real, it has conjugate symmetry, i.e. + Y(l,-m) = Y(l,m)* (where * denotes the complex conjugate). Second, the + diffusion profile should be antipodally symmetric (i.e. S(x) = S(-x)), + implying that all odd l components should be zero. Therefore, only the + even elements are computed. + + Note that the spherical harmonics equations used here differ slightly from + those conventionally used, in that the (-1)^m factor has been omitted. + This should be taken into account in all subsequent calculations. + Each volume in the output image corresponds to a different spherical + harmonic component. Each volume will correspond to the following: + + volume 0: l = 0, m = 0 + volume 1: l = 2, m = -2 (imaginary part of m=2 SH) + volume 2: l = 2, m = -1 (imaginary part of m=1 SH) + volume 3: l = 2, m = 0 + volume 4: l = 2, m = 1 (real part of m=1 SH) + volume 5: l = 2, m = 2 (real part of m=2 SH) + etc... + + + + Example + ------- + + >>> import nipype.interfaces.mrtrix3 as mrt + >>> fod = mrt.EstimateFOD() + >>> fod.inputs.in_file = 'dwi.mif' + >>> fod.inputs.in_mask = 'mask.nii.gz' + >>> fod.inputs.grad_fsl = ('bvecs', 'bvals') + >>> fod.cmdline # doctest: +ELLIPSIS + 'dwi2fod -fslgrad bvecs bvals -mask mask.nii.gz dwi.mif fods.mif' + >>> fod.run() # doctest: +SKIP + """ + + _cmd = 'dwi2fod' + input_spec = EstimateFODInputSpec + output_spec = EstimateFODOutputSpec + + def _list_outputs(self): + outputs = self.output_spec().get() + outputs['out_file'] = op.abspath(self.inputs.out_file) + return outputs \ No newline at end of file diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py b/nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py new file mode 100644 index 0000000000..0a48b68bf6 --- /dev/null +++ b/nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py @@ -0,0 +1,67 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from nipype.testing import assert_equal +from nipype.interfaces.mrtrix3.reconst import EstimateFOD + +def test_EstimateFOD_inputs(): + input_map = dict(args=dict(argstr='%s', + ), + bval_scale=dict(argstr='-bvalue_scaling %s', + ), + environ=dict(nohash=True, + usedefault=True, + ), + grad_file=dict(argstr='-grad %s', + ), + grad_fsl=dict(argstr='-fslgrad %s %s', + ), + ignore_exception=dict(nohash=True, + usedefault=True, + ), + in_dirs=dict(argstr='-directions %s', + ), + in_file=dict(argstr='%s', + mandatory=True, + position=-3, + ), + in_mask=dict(argstr='-mask %s', + ), + max_sh=dict(argstr='-lmax %d', + ), + n_iter=dict(argstr='-niter %d', + ), + neg_lambda=dict(argstr='-neg_lambda %f', + ), + out_file=dict(argstr='%s', + mandatory=True, + position=-1, + usedefault=True, + ), + response=dict(argstr='%s', + mandatory=True, + position=-2, + ), + sh_filter=dict(argstr='-filter %s', + ), + shell=dict(argstr='-shell %f', + sep=',', + ), + terminal_output=dict(nohash=True, + ), + thres=dict(argstr='-threshold %f', + ), + ) + inputs = EstimateFOD.input_spec() + + for key, metadata in input_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(inputs.traits()[key], metakey), value + +def test_EstimateFOD_outputs(): + output_map = dict(out_file=dict(), + ) + outputs = EstimateFOD.output_spec() + + for key, metadata in output_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(outputs.traits()[key], metakey), value + diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_FitTensor.py b/nipype/interfaces/mrtrix3/tests/test_auto_FitTensor.py new file mode 100644 index 0000000000..07b3b47312 --- /dev/null +++ b/nipype/interfaces/mrtrix3/tests/test_auto_FitTensor.py @@ -0,0 +1,52 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from nipype.testing import assert_equal +from nipype.interfaces.mrtrix3.reconst import FitTensor + +def test_FitTensor_inputs(): + input_map = dict(args=dict(argstr='%s', + ), + bval_scale=dict(argstr='-bvalue_scaling %s', + ), + environ=dict(nohash=True, + usedefault=True, + ), + grad_file=dict(argstr='-grad %s', + ), + grad_fsl=dict(argstr='-fslgrad %s %s', + ), + ignore_exception=dict(nohash=True, + usedefault=True, + ), + in_file=dict(argstr='%s', + mandatory=True, + position=-2, + ), + in_mask=dict(argstr='-mask %s', + ), + method=dict(argstr='-method %s', + ), + out_file=dict(argstr='%s', + mandatory=True, + position=-1, + usedefault=True, + ), + reg_term=dict(argstr='-regularisation %f', + ), + terminal_output=dict(nohash=True, + ), + ) + inputs = FitTensor.input_spec() + + for key, metadata in input_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(inputs.traits()[key], metakey), value + +def test_FitTensor_outputs(): + output_map = dict(out_file=dict(), + ) + outputs = FitTensor.output_spec() + + for key, metadata in output_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(outputs.traits()[key], metakey), value + From 85a51a11ec6d96d80bfc9eb2e32699150240f5f9 Mon Sep 17 00:00:00 2001 From: oesteban Date: Tue, 30 Jun 2015 19:31:26 +0200 Subject: [PATCH 14/29] Add dwi2mask, fix auto tests --- nipype/interfaces/mrtrix3/__init__.py | 2 +- nipype/interfaces/mrtrix3/reconst.py | 4 +- .../mrtrix3/tests/test_auto_BrainMask.py | 46 +++++++++++++++ nipype/interfaces/mrtrix3/utils.py | 57 ++++++++++++++++++- nipype/testing/data/response.txt | 0 5 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 nipype/interfaces/mrtrix3/tests/test_auto_BrainMask.py create mode 100644 nipype/testing/data/response.txt diff --git a/nipype/interfaces/mrtrix3/__init__.py b/nipype/interfaces/mrtrix3/__init__.py index 2fe363c48c..26c2e43f31 100644 --- a/nipype/interfaces/mrtrix3/__init__.py +++ b/nipype/interfaces/mrtrix3/__init__.py @@ -2,7 +2,7 @@ # vi: set ft=python sts=4 ts=4 sw=4 et: # -*- coding: utf-8 -*- -from utils import Mesh2PVE, Generate5tt +from utils import Mesh2PVE, Generate5tt, BrainMask from preprocess import ResponseSD, ACTPrepareFSL from tracking import Tractography from reconst import FitTensor, EstimateFOD diff --git a/nipype/interfaces/mrtrix3/reconst.py b/nipype/interfaces/mrtrix3/reconst.py index f5a8506376..9d7bb21488 100644 --- a/nipype/interfaces/mrtrix3/reconst.py +++ b/nipype/interfaces/mrtrix3/reconst.py @@ -201,10 +201,12 @@ class EstimateFOD(CommandLine): >>> import nipype.interfaces.mrtrix3 as mrt >>> fod = mrt.EstimateFOD() >>> fod.inputs.in_file = 'dwi.mif' + >>> fod.inputs.response = 'response.txt' >>> fod.inputs.in_mask = 'mask.nii.gz' >>> fod.inputs.grad_fsl = ('bvecs', 'bvals') >>> fod.cmdline # doctest: +ELLIPSIS - 'dwi2fod -fslgrad bvecs bvals -mask mask.nii.gz dwi.mif fods.mif' + 'dwi2fod -fslgrad bvecs bvals -mask mask.nii.gz dwi.mif response.txt\ + fods.mif' >>> fod.run() # doctest: +SKIP """ diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_BrainMask.py b/nipype/interfaces/mrtrix3/tests/test_auto_BrainMask.py new file mode 100644 index 0000000000..0bcaae1e4d --- /dev/null +++ b/nipype/interfaces/mrtrix3/tests/test_auto_BrainMask.py @@ -0,0 +1,46 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from nipype.testing import assert_equal +from nipype.interfaces.mrtrix3.utils import BrainMask + +def test_BrainMask_inputs(): + input_map = dict(args=dict(argstr='%s', + ), + bval_scale=dict(argstr='-bvalue_scaling %s', + ), + environ=dict(nohash=True, + usedefault=True, + ), + grad_file=dict(argstr='-grad %s', + ), + grad_fsl=dict(argstr='-fslgrad %s %s', + ), + ignore_exception=dict(nohash=True, + usedefault=True, + ), + in_file=dict(argstr='%s', + mandatory=True, + position=-2, + ), + out_file=dict(argstr='%s', + mandatory=True, + position=-1, + usedefault=True, + ), + terminal_output=dict(nohash=True, + ), + ) + inputs = BrainMask.input_spec() + + for key, metadata in input_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(inputs.traits()[key], metakey), value + +def test_BrainMask_outputs(): + output_map = dict(out_file=dict(), + ) + outputs = BrainMask.output_spec() + + for key, metadata in output_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(outputs.traits()[key], metakey), value + diff --git a/nipype/interfaces/mrtrix3/utils.py b/nipype/interfaces/mrtrix3/utils.py index 56893d0ab7..4bad9df0e5 100644 --- a/nipype/interfaces/mrtrix3/utils.py +++ b/nipype/interfaces/mrtrix3/utils.py @@ -22,11 +22,64 @@ from nipype.interfaces.traits_extension import isdefined +class BrainMaskInputSpec(CommandLineInputSpec): + in_file = File(exists=True, argstr='%s', mandatory=True, position=-2, + desc='input diffusion weighted images') + out_file = File( + 'brainmask.mif', argstr='%s', mandatory=True, position=-1, + usedefault=True, desc='output brain mask') + # DW gradient table import options + grad_file = File(exists=True, argstr='-grad %s', + desc='dw gradient scheme (MRTrix format') + grad_fsl = traits.Tuple( + File(exists=True), File(exists=True), argstr='-fslgrad %s %s', + desc='(bvecs, bvals) dw gradient scheme (FSL format') + bval_scale = traits.Enum( + 'yes', 'no', argstr='-bvalue_scaling %s', + desc=('specifies whether the b - values should be scaled by the square' + ' of the corresponding DW gradient norm, as often required for ' + 'multishell or DSI DW acquisition schemes. The default action ' + 'can also be set in the MRtrix config file, under the ' + 'BValueScaling entry. Valid choices are yes / no, true / ' + 'false, 0 / 1 (default: true).')) + +class BrainMaskOutputSpec(TraitedSpec): + out_file = File(exists=True, desc='the output response file') + + +class BrainMask(CommandLine): + + """ + Convert a mesh surface to a partial volume estimation image + + + Example + ------- + + >>> import nipype.interfaces.mrtrix3 as mrt + >>> bmsk = mrt.BrainMask() + >>> bmsk.inputs.in_file = 'dwi.mif' + >>> bmsk.cmdline # doctest: +ELLIPSIS + 'dwi2mask dwi.mif brainmask.mif' + >>> bmsk.run() # doctest: +SKIP + """ + + _cmd = 'dwi2mask' + input_spec = BrainMaskInputSpec + output_spec = BrainMaskOutputSpec + + def _list_outputs(self): + outputs = self.output_spec().get() + outputs['out_file'] = op.abspath(self.inputs.out_file) + return outputs + + + class Mesh2PVEInputSpec(CommandLineInputSpec): in_file = File(exists=True, argstr='%s', mandatory=True, position=-3, - desc='input diffusion weighted images') + desc='input mesh') reference = File(exists=True, argstr='%s', mandatory=True, position=-2, - desc='input diffusion weighted images') + desc='input reference image') in_first = File( exists=True, argstr='-first %s', desc='indicates that the mesh file is provided by FSL FIRST') diff --git a/nipype/testing/data/response.txt b/nipype/testing/data/response.txt new file mode 100644 index 0000000000..e69de29bb2 From 15dd7a88d7429f2eeb3c0ce1fcf794d94dc3fec7 Mon Sep 17 00:00:00 2001 From: oesteban Date: Tue, 30 Jun 2015 21:14:29 +0200 Subject: [PATCH 15/29] Add TensorMetrics interface --- nipype/interfaces/mrtrix3/__init__.py | 2 +- .../mrtrix3/tests/test_auto_TensorMetrics.py | 53 +++++++++++++++++ nipype/interfaces/mrtrix3/utils.py | 59 +++++++++++++++++++ nipype/testing/data/dti.mif | 0 4 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 nipype/interfaces/mrtrix3/tests/test_auto_TensorMetrics.py create mode 100644 nipype/testing/data/dti.mif diff --git a/nipype/interfaces/mrtrix3/__init__.py b/nipype/interfaces/mrtrix3/__init__.py index 26c2e43f31..a01a4f3f55 100644 --- a/nipype/interfaces/mrtrix3/__init__.py +++ b/nipype/interfaces/mrtrix3/__init__.py @@ -2,7 +2,7 @@ # vi: set ft=python sts=4 ts=4 sw=4 et: # -*- coding: utf-8 -*- -from utils import Mesh2PVE, Generate5tt, BrainMask +from utils import Mesh2PVE, Generate5tt, BrainMask, TensorMetrics from preprocess import ResponseSD, ACTPrepareFSL from tracking import Tractography from reconst import FitTensor, EstimateFOD diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_TensorMetrics.py b/nipype/interfaces/mrtrix3/tests/test_auto_TensorMetrics.py new file mode 100644 index 0000000000..4c0f6f97eb --- /dev/null +++ b/nipype/interfaces/mrtrix3/tests/test_auto_TensorMetrics.py @@ -0,0 +1,53 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from nipype.testing import assert_equal +from nipype.interfaces.mrtrix3.utils import TensorMetrics + +def test_TensorMetrics_inputs(): + input_map = dict(args=dict(argstr='%s', + ), + component=dict(argstr='-num %s', + sep=',', + ), + environ=dict(nohash=True, + usedefault=True, + ), + ignore_exception=dict(nohash=True, + usedefault=True, + ), + in_file=dict(argstr='%s', + mandatory=True, + position=-1, + ), + in_mask=dict(argstr='-mask %s', + ), + modulate=dict(argstr='-modulate %s', + ), + out_adc=dict(argstr='-adc %s', + ), + out_eval=dict(argstr='-value %s', + ), + out_evec=dict(argstr='-vector %s', + ), + out_fa=dict(argstr='-fa %s', + ), + terminal_output=dict(nohash=True, + ), + ) + inputs = TensorMetrics.input_spec() + + for key, metadata in input_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(inputs.traits()[key], metakey), value + +def test_TensorMetrics_outputs(): + output_map = dict(out_adc=dict(), + out_eval=dict(), + out_evec=dict(), + out_fa=dict(), + ) + outputs = TensorMetrics.output_spec() + + for key, metadata in output_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(outputs.traits()[key], metakey), value + diff --git a/nipype/interfaces/mrtrix3/utils.py b/nipype/interfaces/mrtrix3/utils.py index 4bad9df0e5..4978ed11f3 100644 --- a/nipype/interfaces/mrtrix3/utils.py +++ b/nipype/interfaces/mrtrix3/utils.py @@ -167,3 +167,62 @@ def _list_outputs(self): outputs = self.output_spec().get() outputs['out_file'] = op.abspath(self.inputs.out_file) return outputs + + +class TensorMetricsInputSpec(CommandLineInputSpec): + in_file = File(exists=True, argstr='%s', mandatory=True, position=-1, + desc='input DTI image') + + out_fa = File(argstr='-fa %s', desc='output FA file') + out_adc = File(argstr='-adc %s', desc='output ADC file') + out_evec = File(argstr='-vector %s', + desc='output selected eigenvector(s) file') + out_eval = File(argstr='-value %s', + desc='output selected eigenvalue(s) file') + component = traits.List( + [1, 2, 3], argstr='-num %s', sep=',', + desc=('specify the desired eigenvalue/eigenvector(s). Note that ' + 'several eigenvalues can be specified as a number sequence')) + in_mask = File(exists=True, argstr='-mask %s', + desc=('only perform computation within the specified binary ' + 'brain mask image')) + modulate = traits.Enum('FA', 'none', 'eval', argstr='-modulate %s', + desc='how to modulate the magnitude of the eigenvectors') + +class TensorMetricsOutputSpec(TraitedSpec): + out_fa = File(desc='output FA file') + out_adc = File(desc='output ADC file') + out_evec = File(desc='output selected eigenvector(s) file') + out_eval = File(desc='output selected eigenvalue(s) file') + + +class TensorMetrics(CommandLine): + + """ + Convert a mesh surface to a partial volume estimation image + + + Example + ------- + + >>> import nipype.interfaces.mrtrix3 as mrt + >>> comp = mrt.TensorMetrics() + >>> comp.inputs.in_file = 'dti.mif' + >>> comp.inputs.out_fa = 'fa.mif' + >>> comp.cmdline # doctest: +ELLIPSIS + 'tensor2metric -fa fa.mif dti.mif' + >>> comp.run() # doctest: +SKIP + """ + + _cmd = 'tensor2metric' + input_spec = TensorMetricsInputSpec + output_spec = TensorMetricsOutputSpec + + def _list_outputs(self): + outputs = self.output_spec().get() + + for k in outputs.keys(): + if isdefined(getattr(self.inputs, k)): + outputs[k] = op.abspath(getattr(self.inputs, k)) + + return outputs \ No newline at end of file diff --git a/nipype/testing/data/dti.mif b/nipype/testing/data/dti.mif new file mode 100644 index 0000000000..e69de29bb2 From 8a5fd2838a7e3f110528a5a318c7740d2b5bff8b Mon Sep 17 00:00:00 2001 From: oesteban Date: Thu, 2 Jul 2015 12:36:30 +0200 Subject: [PATCH 16/29] fix shells options, merge master --- nipype/interfaces/mrtrix3/preprocess.py | 2 +- nipype/interfaces/mrtrix3/reconst.py | 19 ++++++++++--------- .../mrtrix3/tests/test_auto_EstimateFOD.py | 2 +- .../mrtrix3/tests/test_auto_ResponseSD.py | 2 +- nipype/interfaces/mrtrix3/utils.py | 12 +++++++----- 5 files changed, 20 insertions(+), 17 deletions(-) diff --git a/nipype/interfaces/mrtrix3/preprocess.py b/nipype/interfaces/mrtrix3/preprocess.py index 14dfe241d0..e0f1e583eb 100644 --- a/nipype/interfaces/mrtrix3/preprocess.py +++ b/nipype/interfaces/mrtrix3/preprocess.py @@ -46,7 +46,7 @@ class ResponseSDInputSpec(CommandLineInputSpec): # DW Shell selection options - shell = traits.List(traits.Float, sep=',', argstr='-shell %f', + shell = traits.List(traits.Float, sep=',', argstr='-shell %s', desc='specify one or more dw gradient shells') in_mask = File(exists=True, argstr='-mask %s', desc='provide initial mask image') diff --git a/nipype/interfaces/mrtrix3/reconst.py b/nipype/interfaces/mrtrix3/reconst.py index 9d7bb21488..3775f29f93 100644 --- a/nipype/interfaces/mrtrix3/reconst.py +++ b/nipype/interfaces/mrtrix3/reconst.py @@ -21,6 +21,7 @@ from nipype.utils.filemanip import split_filename from nipype.interfaces.traits_extension import isdefined + class FitTensorInputSpec(CommandLineInputSpec): in_file = File(exists=True, argstr='%s', mandatory=True, position=-2, desc='input diffusion weighted images') @@ -30,17 +31,16 @@ class FitTensorInputSpec(CommandLineInputSpec): # General options in_mask = File(exists=True, argstr='-mask %s', - desc=('only perform computation within the specified binary ' - 'brain mask image')) + desc=('only perform computation within the specified ' + 'binary brain mask image')) method = traits.Enum( 'nonlinear', 'loglinear', 'sech', 'rician', argstr='-method %s', desc=('select method used to perform the fitting')) reg_term = traits.Float( 5.e3, argstr='-regularisation %f', - desc=('specify the strength of the regularisation term on the magnitude ' - 'of the tensor elements (default = 5000). This only applies to the ' - 'non-linear methods')) - + desc=('specify the strength of the regularisation term on the ' + 'magnitude of the tensor elements (default = 5000). This ' + 'only applies to the non-linear methods')) # DW gradient table import options grad_file = File(exists=True, argstr='-grad %s', @@ -100,7 +100,8 @@ class EstimateFODInputSpec(CommandLineInputSpec): 'function coefficients for a single fibre population')) out_file = File( 'fods.mif', argstr='%s', mandatory=True, position=-1, - usedefault=True, desc='the output spherical harmonics coefficients image') + usedefault=True, desc=('the output spherical harmonics coefficients' + ' image')) # DW gradient table import options grad_file = File(exists=True, argstr='-grad %s', @@ -118,7 +119,7 @@ class EstimateFODInputSpec(CommandLineInputSpec): 'false, 0 / 1 (default: true).')) # DW Shell selection options - shell = traits.List(traits.Float, sep=',', argstr='-shell %f', + shell = traits.List(traits.Float, sep=',', argstr='-shell %s', desc='specify one or more dw gradient shells') # Spherical deconvolution options @@ -217,4 +218,4 @@ class EstimateFOD(CommandLine): def _list_outputs(self): outputs = self.output_spec().get() outputs['out_file'] = op.abspath(self.inputs.out_file) - return outputs \ No newline at end of file + return outputs diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py b/nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py index 0a48b68bf6..d0ffbdeb74 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py @@ -42,7 +42,7 @@ def test_EstimateFOD_inputs(): ), sh_filter=dict(argstr='-filter %s', ), - shell=dict(argstr='-shell %f', + shell=dict(argstr='-shell %s', sep=',', ), terminal_output=dict(nohash=True, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_ResponseSD.py b/nipype/interfaces/mrtrix3/tests/test_auto_ResponseSD.py index 059df98430..13bb06a2d7 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_ResponseSD.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_ResponseSD.py @@ -40,7 +40,7 @@ def test_ResponseSD_inputs(): ), out_sf=dict(argstr='-sf %s', ), - shell=dict(argstr='-shell %f', + shell=dict(argstr='-shell %s', sep=',', ), terminal_output=dict(nohash=True, diff --git a/nipype/interfaces/mrtrix3/utils.py b/nipype/interfaces/mrtrix3/utils.py index 4978ed11f3..bde3f4a06a 100644 --- a/nipype/interfaces/mrtrix3/utils.py +++ b/nipype/interfaces/mrtrix3/utils.py @@ -43,6 +43,7 @@ class BrainMaskInputSpec(CommandLineInputSpec): 'BValueScaling entry. Valid choices are yes / no, true / ' 'false, 0 / 1 (default: true).')) + class BrainMaskOutputSpec(TraitedSpec): out_file = File(exists=True, desc='the output response file') @@ -74,7 +75,6 @@ def _list_outputs(self): return outputs - class Mesh2PVEInputSpec(CommandLineInputSpec): in_file = File(exists=True, argstr='%s', mandatory=True, position=-3, desc='input mesh') @@ -184,10 +184,12 @@ class TensorMetricsInputSpec(CommandLineInputSpec): desc=('specify the desired eigenvalue/eigenvector(s). Note that ' 'several eigenvalues can be specified as a number sequence')) in_mask = File(exists=True, argstr='-mask %s', - desc=('only perform computation within the specified binary ' - 'brain mask image')) + desc=('only perform computation within the specified binary' + ' brain mask image')) modulate = traits.Enum('FA', 'none', 'eval', argstr='-modulate %s', - desc='how to modulate the magnitude of the eigenvectors') + desc=('how to modulate the magnitude of the' + ' eigenvectors')) + class TensorMetricsOutputSpec(TraitedSpec): out_fa = File(desc='output FA file') @@ -225,4 +227,4 @@ def _list_outputs(self): if isdefined(getattr(self.inputs, k)): outputs[k] = op.abspath(getattr(self.inputs, k)) - return outputs \ No newline at end of file + return outputs From 204aa89a776325cc497a1ef541dac92fbc05c224 Mon Sep 17 00:00:00 2001 From: oesteban Date: Thu, 2 Jul 2015 18:01:13 +0200 Subject: [PATCH 17/29] new base for MRTrix3 interfaces, new nthreads input --- nipype/interfaces/mrtrix3/base.py | 61 ++++++++++++++++++ nipype/interfaces/mrtrix3/preprocess.py | 21 +------ nipype/interfaces/mrtrix3/reconst.py | 62 +++++-------------- .../mrtrix3/tests/test_auto_BrainMask.py | 2 + .../mrtrix3/tests/test_auto_EstimateFOD.py | 2 + .../mrtrix3/tests/test_auto_FitTensor.py | 2 + .../mrtrix3/tests/test_auto_MRTrix3Base.py | 22 +++++++ .../mrtrix3/tests/test_auto_ResponseSD.py | 2 + .../mrtrix3/tests/test_auto_Tractography.py | 2 + nipype/interfaces/mrtrix3/tracking.py | 25 ++------ nipype/interfaces/mrtrix3/utils.py | 17 +---- 11 files changed, 121 insertions(+), 97 deletions(-) create mode 100644 nipype/interfaces/mrtrix3/base.py create mode 100644 nipype/interfaces/mrtrix3/tests/test_auto_MRTrix3Base.py diff --git a/nipype/interfaces/mrtrix3/base.py b/nipype/interfaces/mrtrix3/base.py new file mode 100644 index 0000000000..b1a6aea524 --- /dev/null +++ b/nipype/interfaces/mrtrix3/base.py @@ -0,0 +1,61 @@ +# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- +# vi: set ft=python sts=4 ts=4 sw=4 et: +# -*- coding: utf-8 -*- + +""" + Change directory to provide relative paths for doctests + >>> import os + >>> filepath = os.path.dirname(os.path.realpath(__file__ )) + >>> datadir = os.path.realpath(os.path.join(filepath, + ... '../../testing/data')) + >>> os.chdir(datadir) + +""" +import os +import os.path as op + +from nipype.interfaces.base import ( + CommandLineInputSpec, CommandLine, traits, TraitedSpec, File, + InputMultiPath) + +from nipype.utils.filemanip import split_filename +from nipype.interfaces.traits_extension import isdefined + +from ... import logging +logger = logging.getLogger('interface') + + +class MRTrix3BaseInputSpec(CommandLineInputSpec): + nthreads = traits.Int( + argstr='-nthreads %d', desc='number of threads. if zero, the number' + ' of available cpus will be used') + # DW gradient table import options + grad_file = File(exists=True, argstr='-grad %s', + desc='dw gradient scheme (MRTrix format') + grad_fsl = traits.Tuple( + File(exists=True), File(exists=True), argstr='-fslgrad %s %s', + desc='(bvecs, bvals) dw gradient scheme (FSL format') + bval_scale = traits.Enum( + 'yes', 'no', argstr='-bvalue_scaling %s', + desc='specifies whether the b - values should be scaled by the square' + ' of the corresponding DW gradient norm, as often required for ' + 'multishell or DSI DW acquisition schemes. The default action ' + 'can also be set in the MRtrix config file, under the ' + 'BValueScaling entry. Valid choices are yes / no, true / ' + 'false, 0 / 1 (default: true).') + + +class MRTrix3Base(CommandLine): + + def _format_arg(self, name, trait_spec, value): + if name == 'nthreads' and value == 0: + value = 1 + try: + from multiprocessing import cpu_count + value = cpu_count() + except: + logger.warn('Number of threads could not be computed') + pass + return trait_spec.argstr % value + + return super(MRTrix3Base, self)._format_arg(name, trait_spec, value) diff --git a/nipype/interfaces/mrtrix3/preprocess.py b/nipype/interfaces/mrtrix3/preprocess.py index e0f1e583eb..a853065fdf 100644 --- a/nipype/interfaces/mrtrix3/preprocess.py +++ b/nipype/interfaces/mrtrix3/preprocess.py @@ -14,6 +14,7 @@ import os import os.path as op +from base import MRTrix3BaseInputSpec, MRTrix3Base from nipype.interfaces.base import ( CommandLineInputSpec, CommandLine, traits, TraitedSpec, File) @@ -21,7 +22,7 @@ from nipype.interfaces.traits_extension import isdefined -class ResponseSDInputSpec(CommandLineInputSpec): +class ResponseSDInputSpec(MRTrix3BaseInputSpec): in_file = File(exists=True, argstr='%s', mandatory=True, position=-2, desc='input diffusion weighted images') @@ -29,23 +30,7 @@ class ResponseSDInputSpec(CommandLineInputSpec): 'response.txt', argstr='%s', mandatory=True, position=-1, usedefault=True, desc='output file containing SH coefficients') - # DW gradient table import options - grad_file = File(exists=True, argstr='-grad %s', - desc='dw gradient scheme (MRTrix format') - grad_fsl = traits.Tuple( - File(exists=True), File(exists=True), argstr='-fslgrad %s %s', - desc='(bvecs, bvals) dw gradient scheme (FSL format') - bval_scale = traits.Enum( - 'yes', 'no', argstr='-bvalue_scaling %s', - desc=('specifies whether the b - values should be scaled by the square' - ' of the corresponding DW gradient norm, as often required for ' - 'multishell or DSI DW acquisition schemes. The default action ' - 'can also be set in the MRtrix config file, under the ' - 'BValueScaling entry. Valid choices are yes / no, true / ' - 'false, 0 / 1 (default: true).')) - # DW Shell selection options - shell = traits.List(traits.Float, sep=',', argstr='-shell %s', desc='specify one or more dw gradient shells') in_mask = File(exists=True, argstr='-mask %s', @@ -92,7 +77,7 @@ class ResponseSDOutputSpec(TraitedSpec): out_sf = File(desc=('mask containing single-fibre voxels')) -class ResponseSD(CommandLine): +class ResponseSD(MRTrix3Base): """ Generate an appropriate response function from the image data for diff --git a/nipype/interfaces/mrtrix3/reconst.py b/nipype/interfaces/mrtrix3/reconst.py index 3775f29f93..2916b4bdac 100644 --- a/nipype/interfaces/mrtrix3/reconst.py +++ b/nipype/interfaces/mrtrix3/reconst.py @@ -14,6 +14,7 @@ import os import os.path as op +from base import MRTrix3BaseInputSpec, MRTrix3Base from nipype.interfaces.base import ( CommandLineInputSpec, CommandLine, traits, TraitedSpec, File, InputMultiPath) @@ -22,7 +23,7 @@ from nipype.interfaces.traits_extension import isdefined -class FitTensorInputSpec(CommandLineInputSpec): +class FitTensorInputSpec(MRTrix3BaseInputSpec): in_file = File(exists=True, argstr='%s', mandatory=True, position=-2, desc='input diffusion weighted images') out_file = File( @@ -42,27 +43,12 @@ class FitTensorInputSpec(CommandLineInputSpec): 'magnitude of the tensor elements (default = 5000). This ' 'only applies to the non-linear methods')) - # DW gradient table import options - grad_file = File(exists=True, argstr='-grad %s', - desc='dw gradient scheme (MRTrix format') - grad_fsl = traits.Tuple( - File(exists=True), File(exists=True), argstr='-fslgrad %s %s', - desc='(bvecs, bvals) dw gradient scheme (FSL format') - bval_scale = traits.Enum( - 'yes', 'no', argstr='-bvalue_scaling %s', - desc=('specifies whether the b - values should be scaled by the square' - ' of the corresponding DW gradient norm, as often required for ' - 'multishell or DSI DW acquisition schemes. The default action ' - 'can also be set in the MRtrix config file, under the ' - 'BValueScaling entry. Valid choices are yes / no, true / ' - 'false, 0 / 1 (default: true).')) - class FitTensorOutputSpec(TraitedSpec): out_file = File(exists=True, desc='the output DTI file') -class FitTensor(CommandLine): +class FitTensor(MRTrix3Base): """ Convert diffusion-weighted images to tensor images @@ -91,7 +77,7 @@ def _list_outputs(self): return outputs -class EstimateFODInputSpec(CommandLineInputSpec): +class EstimateFODInputSpec(MRTrix3BaseInputSpec): in_file = File(exists=True, argstr='%s', mandatory=True, position=-3, desc='input diffusion weighted images') response = File( @@ -103,21 +89,6 @@ class EstimateFODInputSpec(CommandLineInputSpec): usedefault=True, desc=('the output spherical harmonics coefficients' ' image')) - # DW gradient table import options - grad_file = File(exists=True, argstr='-grad %s', - desc='dw gradient scheme (MRTrix format') - grad_fsl = traits.Tuple( - File(exists=True), File(exists=True), argstr='-fslgrad %s %s', - desc='(bvecs, bvals) dw gradient scheme (FSL format') - bval_scale = traits.Enum( - 'yes', 'no', argstr='-bvalue_scaling %s', - desc=('specifies whether the b - values should be scaled by the square' - ' of the corresponding DW gradient norm, as often required for ' - 'multishell or DSI DW acquisition schemes. The default action ' - 'can also be set in the MRtrix config file, under the ' - 'BValueScaling entry. Valid choices are yes / no, true / ' - 'false, 0 / 1 (default: true).')) - # DW Shell selection options shell = traits.List(traits.Float, sep=',', argstr='-shell %s', desc='specify one or more dw gradient shells') @@ -130,34 +101,35 @@ class EstimateFODInputSpec(CommandLineInputSpec): in_dirs = File( exists=True, argstr='-directions %s', desc=('specify the directions over which to apply the non-negativity ' - 'constraint (by default, the built-in 300 direction set is used). ' - 'These should be supplied as a text file containing the [ az el ] ' - 'pairs for the directions.')) + 'constraint (by default, the built-in 300 direction set is ' + 'used). These should be supplied as a text file containing the ' + '[ az el ] pairs for the directions.')) sh_filter = File( exists=True, argstr='-filter %s', desc=('the linear frequency filtering parameters used for the initial ' 'linear spherical deconvolution step (default = [ 1 1 1 0 0 ]). ' - 'These should be supplied as a text file containing the filtering ' - 'coefficients for each even harmonic order.')) + 'These should be supplied as a text file containing the ' + 'filtering coefficients for each even harmonic order.')) neg_lambda = traits.Float( 1.0, argstr='-neg_lambda %f', - desc=('the regularisation parameter lambda that controls the strength of ' - 'the non-negativity constraint')) + desc=('the regularisation parameter lambda that controls the strength' + ' of the non-negativity constraint')) thres = traits.Float( 0.0, argstr='-threshold %f', - desc=('the threshold below which the amplitude of the FOD is assumed to be ' - 'zero, expressed as an absolute amplitude')) + desc=('the threshold below which the amplitude of the FOD is assumed ' + 'to be zero, expressed as an absolute amplitude')) - n_iter = traits.Int(50, argstr='-niter %d', desc=('the maximum number of iterat' - 'ions to perform for each voxel')) + n_iter = traits.Int( + 50, argstr='-niter %d', desc=('the maximum number of iterations ' + 'to perform for each voxel')) class EstimateFODOutputSpec(TraitedSpec): out_file = File(exists=True, desc='the output response file') -class EstimateFOD(CommandLine): +class EstimateFOD(MRTrix3Base): """ Convert diffusion-weighted images to tensor images diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_BrainMask.py b/nipype/interfaces/mrtrix3/tests/test_auto_BrainMask.py index 0bcaae1e4d..f230719694 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_BrainMask.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_BrainMask.py @@ -21,6 +21,8 @@ def test_BrainMask_inputs(): mandatory=True, position=-2, ), + nthreads=dict(argstr='-nthreads %d', + ), out_file=dict(argstr='%s', mandatory=True, position=-1, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py b/nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py index d0ffbdeb74..809685b752 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py @@ -31,6 +31,8 @@ def test_EstimateFOD_inputs(): ), neg_lambda=dict(argstr='-neg_lambda %f', ), + nthreads=dict(argstr='-nthreads %d', + ), out_file=dict(argstr='%s', mandatory=True, position=-1, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_FitTensor.py b/nipype/interfaces/mrtrix3/tests/test_auto_FitTensor.py index 07b3b47312..1c7a31e78a 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_FitTensor.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_FitTensor.py @@ -25,6 +25,8 @@ def test_FitTensor_inputs(): ), method=dict(argstr='-method %s', ), + nthreads=dict(argstr='-nthreads %d', + ), out_file=dict(argstr='%s', mandatory=True, position=-1, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_MRTrix3Base.py b/nipype/interfaces/mrtrix3/tests/test_auto_MRTrix3Base.py new file mode 100644 index 0000000000..3595f3acd9 --- /dev/null +++ b/nipype/interfaces/mrtrix3/tests/test_auto_MRTrix3Base.py @@ -0,0 +1,22 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from nipype.testing import assert_equal +from nipype.interfaces.mrtrix3.base import MRTrix3Base + +def test_MRTrix3Base_inputs(): + input_map = dict(args=dict(argstr='%s', + ), + environ=dict(nohash=True, + usedefault=True, + ), + ignore_exception=dict(nohash=True, + usedefault=True, + ), + terminal_output=dict(nohash=True, + ), + ) + inputs = MRTrix3Base.input_spec() + + for key, metadata in input_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(inputs.traits()[key], metakey), value + diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_ResponseSD.py b/nipype/interfaces/mrtrix3/tests/test_auto_ResponseSD.py index 13bb06a2d7..c1e1b6094e 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_ResponseSD.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_ResponseSD.py @@ -33,6 +33,8 @@ def test_ResponseSD_inputs(): ), max_sh=dict(argstr='-lmax %d', ), + nthreads=dict(argstr='-nthreads %d', + ), out_file=dict(argstr='%s', mandatory=True, position=-1, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py b/nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py index a8fa1c49fa..0d64f9e6c5 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py @@ -56,6 +56,8 @@ def test_Tractography_inputs(): ), noprecompt=dict(argstr='-noprecomputed', ), + nthreads=dict(argstr='-nthreads %d', + ), out_file=dict(argstr='%s', mandatory=True, position=-1, diff --git a/nipype/interfaces/mrtrix3/tracking.py b/nipype/interfaces/mrtrix3/tracking.py index ab3dc494e9..b90ad6aab7 100644 --- a/nipype/interfaces/mrtrix3/tracking.py +++ b/nipype/interfaces/mrtrix3/tracking.py @@ -14,6 +14,7 @@ import os import os.path as op +from base import MRTrix3BaseInputSpec, MRTrix3Base from nipype.interfaces.base import ( CommandLineInputSpec, CommandLine, traits, TraitedSpec, File) @@ -21,7 +22,7 @@ from nipype.interfaces.traits_extension import isdefined -class TractographyInputSpec(CommandLineInputSpec): +class TractographyInputSpec(MRTrix3BaseInputSpec): sph_trait = traits.Tuple(traits.Float, traits.Float, traits.Float, traits.Float, argstr='%f,%f,%f,%f') @@ -120,7 +121,7 @@ class TractographyInputSpec(CommandLineInputSpec): 'include regions')) downsample = traits.Float( argstr='-downsample %f', - desc=('downsample the generated streamlines to reduce output file size')) + desc='downsample the generated streamlines to reduce output file size') # Anatomically-Constrained Tractography options act_file = File( @@ -171,7 +172,8 @@ class TractographyInputSpec(CommandLineInputSpec): ' while this seeding mechanism improves the distribution of' ' reconstructed streamlines density, it should NOT be used ' 'as a substitute for the SIFT method itself.')) - max_seed_attempts = traits.Int(argstr='-max_seed_attempts %d', + max_seed_attempts = traits.Int( + argstr='-max_seed_attempts %d', desc=('set the maximum number of times that the tracking ' 'algorithm should attempt to find an appropriate tracking' ' direction from a given seed point')) @@ -180,21 +182,6 @@ class TractographyInputSpec(CommandLineInputSpec): desc=('output the seed location of all successful streamlines to' ' a file')) - # DW gradient table import options - grad_file = File(exists=True, argstr='-grad %s', - desc='dw gradient scheme (MRTrix format') - grad_fsl = traits.Tuple( - File(exists=True), File(exists=True), argstr='-fslgrad %s %s', - desc='(bvecs, bvals) dw gradient scheme (FSL format') - bval_scale = traits.Enum( - 'yes', 'no', argstr='-bvalue_scaling %s', - desc=('specifies whether the b - values should be scaled by the square' - ' of the corresponding DW gradient norm, as often required for ' - 'multishell or DSI DW acquisition schemes. The default action ' - 'can also be set in the MRtrix config file, under the ' - 'BValueScaling entry. Valid choices are yes / no, true / ' - 'false, 0 / 1 (default: true).')) - class TractographyOutputSpec(TraitedSpec): out_file = File(exists=True, desc='the output filtered tracks') @@ -202,7 +189,7 @@ class TractographyOutputSpec(TraitedSpec): ' streamlines to a file')) -class Tractography(CommandLine): +class Tractography(MRTrix3Base): """ Performs streamlines tractography after selecting the appropriate diff --git a/nipype/interfaces/mrtrix3/utils.py b/nipype/interfaces/mrtrix3/utils.py index bde3f4a06a..f32d6e09d0 100644 --- a/nipype/interfaces/mrtrix3/utils.py +++ b/nipype/interfaces/mrtrix3/utils.py @@ -14,6 +14,7 @@ import os import os.path as op +from base import MRTrix3BaseInputSpec, MRTrix3Base from nipype.interfaces.base import ( CommandLineInputSpec, CommandLine, traits, TraitedSpec, File, InputMultiPath) @@ -22,26 +23,12 @@ from nipype.interfaces.traits_extension import isdefined -class BrainMaskInputSpec(CommandLineInputSpec): +class BrainMaskInputSpec(MRTrix3BaseInputSpec): in_file = File(exists=True, argstr='%s', mandatory=True, position=-2, desc='input diffusion weighted images') out_file = File( 'brainmask.mif', argstr='%s', mandatory=True, position=-1, usedefault=True, desc='output brain mask') - # DW gradient table import options - grad_file = File(exists=True, argstr='-grad %s', - desc='dw gradient scheme (MRTrix format') - grad_fsl = traits.Tuple( - File(exists=True), File(exists=True), argstr='-fslgrad %s %s', - desc='(bvecs, bvals) dw gradient scheme (FSL format') - bval_scale = traits.Enum( - 'yes', 'no', argstr='-bvalue_scaling %s', - desc=('specifies whether the b - values should be scaled by the square' - ' of the corresponding DW gradient norm, as often required for ' - 'multishell or DSI DW acquisition schemes. The default action ' - 'can also be set in the MRtrix config file, under the ' - 'BValueScaling entry. Valid choices are yes / no, true / ' - 'false, 0 / 1 (default: true).')) class BrainMaskOutputSpec(TraitedSpec): From e28dea50ce02e3443f343bddc6710ded60cb2c53 Mon Sep 17 00:00:00 2001 From: oesteban Date: Fri, 3 Jul 2015 15:40:26 +0200 Subject: [PATCH 18/29] add tckmap interface --- nipype/interfaces/base.py | 6 +- nipype/interfaces/dipy/tensors.py | 10 +- nipype/interfaces/fsl/__init__.py | 2 +- nipype/interfaces/fsl/utils.py | 8 +- nipype/interfaces/mrtrix3/__init__.py | 2 +- .../mrtrix3/tests/test_auto_ComputeTDI.py | 74 ++++++++++ nipype/interfaces/mrtrix3/utils.py | 138 +++++++++++++++++- .../semtools/diffusion/diffusion.py | 16 +- .../diffusion/tractography/fiberprocess.py | 4 +- .../diffusion/tractography/fibertrack.py | 2 +- nipype/testing/data/tdi.mif | 0 nipype/testing/data/von-ray_errmap.nii.gz | Bin 107 -> 107 bytes nipype/testing/data/von_errmap.nii.gz | Bin 96 -> 96 bytes nipype/utils/nipype2boutiques.py | 26 ++-- nipype/utils/nipype_cmd.py | 14 +- nipype/utils/tests/test_cmd.py | 28 ++-- 16 files changed, 270 insertions(+), 60 deletions(-) create mode 100644 nipype/interfaces/mrtrix3/tests/test_auto_ComputeTDI.py create mode 100644 nipype/testing/data/tdi.mif diff --git a/nipype/interfaces/base.py b/nipype/interfaces/base.py index 7917d6e852..81100b9fbd 100644 --- a/nipype/interfaces/base.py +++ b/nipype/interfaces/base.py @@ -1349,9 +1349,9 @@ def _terminal_output_update(self): def set_default_terminal_output(cls, output_type): """Set the default terminal output for CommandLine Interfaces. - This method is used to set default terminal output for - CommandLine Interfaces. However, setting this will not - update the output type for any existing instances. For these, + This method is used to set default terminal output for + CommandLine Interfaces. However, setting this will not + update the output type for any existing instances. For these, assign the .inputs.terminal_output. """ diff --git a/nipype/interfaces/dipy/tensors.py b/nipype/interfaces/dipy/tensors.py index e07983db13..ab4e7be3aa 100644 --- a/nipype/interfaces/dipy/tensors.py +++ b/nipype/interfaces/dipy/tensors.py @@ -32,7 +32,7 @@ def tensor_fitting(data, bvals, bvecs, mask_file=None): """ Use dipy to fit DTI - + Parameters ---------- in_file : str @@ -58,7 +58,7 @@ def tensor_fitting(data, bvals, bvecs, mask_file=None): # Load information about the gradients: gtab = grad.gradient_table(self.inputs.bvals, self.inputs.bvecs) - + # Fit it tenmodel = dti.TensorModel(gtab) return tenmodel.fit(data, mask), affine @@ -84,7 +84,7 @@ class DTIOutputSpec(TraitedSpec): class DTI(BaseInterface): """ Calculates the diffusion tensor model parameters - + Example ------- @@ -99,7 +99,7 @@ class DTI(BaseInterface): output_spec = DTIOutputSpec def _run_interface(self, runtime): - ten_fit, affine = tensor_fitting(self.inputs.in_file, + ten_fit, affine = tensor_fitting(self.inputs.in_file, self.inputs.bvals, self.inputs.bvecs, self.inputs.mask_file) @@ -124,7 +124,7 @@ def _gen_filename(self, name): def _gen_outfilename(self): _, name, _ = split_filename(self.inputs.in_file) return name + '_dti.nii' - + class TensorModeInputSpec(TraitedSpec): in_file = File(exists=True, mandatory=True, diff --git a/nipype/interfaces/fsl/__init__.py b/nipype/interfaces/fsl/__init__.py index c97f4fbec7..7d463056ec 100644 --- a/nipype/interfaces/fsl/__init__.py +++ b/nipype/interfaces/fsl/__init__.py @@ -16,7 +16,7 @@ ImageStats, FilterRegressor, Overlay, Slicer, PlotTimeSeries, PlotMotionParams, ConvertXFM, SwapDimensions, PowerSpectrum, Reorient2Std, - Complex, InvWarp, WarpUtils, ConvertWarp, WarpPoints, + Complex, InvWarp, WarpUtils, ConvertWarp, WarpPoints, WarpPointsToStd, RobustFOV) from .epi import (PrepareFieldmap, TOPUP, ApplyTOPUP, Eddy, EPIDeWarp, diff --git a/nipype/interfaces/fsl/utils.py b/nipype/interfaces/fsl/utils.py index 48db65cf7a..763f26606b 100644 --- a/nipype/interfaces/fsl/utils.py +++ b/nipype/interfaces/fsl/utils.py @@ -36,10 +36,10 @@ class RobustFOVInputSpec(FSLCommandInputSpec): desc='input filename', argstr='-i %s', position=0, mandatory=True) out_roi = File(desc="ROI volume output name", argstr="-r %s", - name_source=['in_file'], hash_files=False, + name_source=['in_file'], hash_files=False, name_template='%s_ROI') - - + + class RobustFOVOutputSpec(TraitedSpec): out_roi = File(exists=True, desc="ROI volume output name") @@ -48,7 +48,7 @@ class RobustFOV(FSLCommand): _cmd = 'robustfov' input_spec = RobustFOVInputSpec output_spec = RobustFOVOutputSpec - + class ImageMeantsInputSpec(FSLCommandInputSpec): in_file = File(exists=True, diff --git a/nipype/interfaces/mrtrix3/__init__.py b/nipype/interfaces/mrtrix3/__init__.py index a01a4f3f55..e22c4d5cec 100644 --- a/nipype/interfaces/mrtrix3/__init__.py +++ b/nipype/interfaces/mrtrix3/__init__.py @@ -2,7 +2,7 @@ # vi: set ft=python sts=4 ts=4 sw=4 et: # -*- coding: utf-8 -*- -from utils import Mesh2PVE, Generate5tt, BrainMask, TensorMetrics +from utils import Mesh2PVE, Generate5tt, BrainMask, TensorMetrics, ComputeTDI from preprocess import ResponseSD, ACTPrepareFSL from tracking import Tractography from reconst import FitTensor, EstimateFOD diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_ComputeTDI.py b/nipype/interfaces/mrtrix3/tests/test_auto_ComputeTDI.py new file mode 100644 index 0000000000..8f6a1122fa --- /dev/null +++ b/nipype/interfaces/mrtrix3/tests/test_auto_ComputeTDI.py @@ -0,0 +1,74 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from nipype.testing import assert_equal +from nipype.interfaces.mrtrix3.utils import ComputeTDI + +def test_ComputeTDI_inputs(): + input_map = dict(args=dict(argstr='%s', + ), + contrast=dict(argstr='-constrast %s', + ), + data_type=dict(argstr='-datatype %s', + ), + dixel=dict(argstr='-dixel %s', + ), + ends_only=dict(argstr='-ends_only', + ), + environ=dict(nohash=True, + usedefault=True, + ), + fwhm_tck=dict(argstr='-fwhm_tck %f', + ), + ignore_exception=dict(nohash=True, + usedefault=True, + ), + in_file=dict(argstr='%s', + mandatory=True, + position=-2, + ), + in_map=dict(argstr='-image %s', + ), + map_zero=dict(argstr='-map_zero', + ), + max_tod=dict(argstr='-tod %d', + ), + nthreads=dict(argstr='-nthreads %d', + ), + out_file=dict(argstr='%s', + position=-1, + usedefault=True, + ), + precise=dict(argstr='-precise', + ), + reference=dict(argstr='-template %s', + ), + stat_tck=dict(argstr='-stat_tck %s', + ), + stat_vox=dict(argstr='-stat_vox %s', + ), + tck_weights=dict(argstr='-tck_weights_in %s', + ), + terminal_output=dict(nohash=True, + ), + upsample=dict(argstr='-upsample %d', + ), + use_dec=dict(argstr='-dec', + ), + vox_size=dict(argstr='-vox %s', + sep=',', + ), + ) + inputs = ComputeTDI.input_spec() + + for key, metadata in input_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(inputs.traits()[key], metakey), value + +def test_ComputeTDI_outputs(): + output_map = dict(out_file=dict(), + ) + outputs = ComputeTDI.output_spec() + + for key, metadata in output_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(outputs.traits()[key], metakey), value + diff --git a/nipype/interfaces/mrtrix3/utils.py b/nipype/interfaces/mrtrix3/utils.py index f32d6e09d0..79e3cee072 100644 --- a/nipype/interfaces/mrtrix3/utils.py +++ b/nipype/interfaces/mrtrix3/utils.py @@ -188,7 +188,7 @@ class TensorMetricsOutputSpec(TraitedSpec): class TensorMetrics(CommandLine): """ - Convert a mesh surface to a partial volume estimation image + Compute metrics from tensors Example @@ -215,3 +215,139 @@ def _list_outputs(self): outputs[k] = op.abspath(getattr(self.inputs, k)) return outputs + + +class ComputeTDIInputSpec(CommandLineInputSpec): + in_file = File(exists=True, argstr='%s', mandatory=True, position=-2, + desc='input tractography') + out_file = File('tdi.mif', argstr='%s', usedefault=True, position=-1, + desc='output TDI file') + reference = File( + exists=True, argstr='-template %s', desc='a reference' + 'image to be used as template') + vox_size = traits.List(traits.Int, argstr='-vox %s', sep=',', + desc='voxel dimensions') + data_type = traits.Enum('float', 'unsigned int', argstr='-datatype %s', + desc='specify output image data type') + use_dec = traits.Bool(argstr='-dec', desc='perform mapping in DEC space') + dixel = File('dixels.txt', argstr='-dixel %s', desc='map streamlines to' + 'dixels within each voxel. Directions are stored as' + 'azimuth elevation pairs.') + max_tod = traits.Int(argstr='-tod %d', desc='generate a Track Orientation ' + 'Distribution (TOD) in each voxel.') + + contrast = traits.Enum('tdi', 'length', 'invlength', 'scalar_map', + 'scalar_map_conut', 'fod_amp', 'curvature', + argstr='-constrast %s', desc='define the desired ' + 'form of contrast for the output image') + in_map = File(exists=True, argstr='-image %s', desc='provide the' + 'scalar image map for generating images with ' + '\'scalar_map\' contrasts, or the SHs image for fod_amp') + + stat_vox = traits.Enum('sum', 'min', 'mean', 'max', argstr='-stat_vox %s', + desc='define the statistic for choosing the final' + 'voxel intesities for a given contrast') + stat_tck = traits.Enum( + 'mean', 'sum', 'min', 'max', 'median', 'mean_nonzero', 'gaussian', + 'ends_min', 'ends_mean', 'ends_max', 'ends_prod', + argstr='-stat_tck %s', desc='define the statistic for choosing ' + 'the contribution to be made by each streamline as a function of' + ' the samples taken along their lengths.') + + fwhm_tck = traits.Float( + argstr='-fwhm_tck %f', desc='define the statistic for choosing the' + ' contribution to be made by each streamline as a function of the ' + 'samples taken along their lengths') + + map_zero = traits.Bool( + argstr='-map_zero', desc='if a streamline has zero contribution based ' + 'on the contrast & statistic, typically it is not mapped; use this ' + 'option to still contribute to the map even if this is the case ' + '(these non-contributing voxels can then influence the mean value in ' + 'each voxel of the map)') + + upsample = traits.Int(argstr='-upsample %d', desc='upsample the tracks by' + ' some ratio using Hermite interpolation before ' + 'mappping') + + precise = traits.Bool( + argstr='-precise', desc='use a more precise streamline mapping ' + 'strategy, that accurately quantifies the length through each voxel ' + '(these lengths are then taken into account during TWI calculation)') + ends_only = traits.Bool(argstr='-ends_only', desc='only map the streamline' + ' endpoints to the image') + + tck_weights = File(exists=True, argstr='-tck_weights_in %s', desc='specify' + ' a text scalar file containing the streamline weights') + nthreads = traits.Int( + argstr='-nthreads %d', desc='number of threads. if zero, the number' + ' of available cpus will be used') + + +class ComputeTDIOutputSpec(TraitedSpec): + out_file = File(desc='output TDI file') + + +class ComputeTDI(MRTrix3Base): + + """ + Use track data as a form of contrast for producing a high-resolution + image. + + .. admonition:: References + + * For TDI or DEC TDI: Calamante, F.; Tournier, J.-D.; Jackson, G. D. & + Connelly, A. Track-density imaging (TDI): Super-resolution white + matter imaging using whole-brain track-density mapping. NeuroImage, + 2010, 53, 1233-1243 + + * If using -contrast length and -stat_vox mean: Pannek, K.; Mathias, + J. L.; Bigler, E. D.; Brown, G.; Taylor, J. D. & Rose, S. E. The + average pathlength map: A diffusion MRI tractography-derived index + for studying brain pathology. NeuroImage, 2011, 55, 133-141 + + * If using -dixel option with TDI contrast only: Smith, R.E., Tournier, + J-D., Calamante, F., Connelly, A. A novel paradigm for automated + segmentation of very large whole-brain probabilistic tractography + data sets. In proc. ISMRM, 2011, 19, 673 + + * If using -dixel option with any other contrast: Pannek, K., Raffelt, + D., Salvado, O., Rose, S. Incorporating directional information in + diffusion tractography derived maps: angular track imaging (ATI). + In Proc. ISMRM, 2012, 20, 1912 + + * If using -tod option: Dhollander, T., Emsell, L., Van Hecke, W., Maes, + F., Sunaert, S., Suetens, P. Track Orientation Density Imaging (TODI) + and Track Orientation Distribution (TOD) based tractography. + NeuroImage, 2014, 94, 312-336 + + * If using other contrasts / statistics: Calamante, F.; Tournier, J.-D.; + Smith, R. E. & Connelly, A. A generalised framework for + super-resolution track-weighted imaging. NeuroImage, 2012, 59, + 2494-2503 + + * If using -precise mapping option: Smith, R. E.; Tournier, J.-D.; + Calamante, F. & Connelly, A. SIFT: Spherical-deconvolution informed + filtering of tractograms. NeuroImage, 2013, 67, 298-312 (Appendix 3) + + + + Example + ------- + + >>> import nipype.interfaces.mrtrix3 as mrt + >>> tdi = mrt.ComputeTDI() + >>> tdi.inputs.in_file = 'dti.mif' + >>> tdi.cmdline # doctest: +ELLIPSIS + 'tckmap dti.mif tdi.mif' + >>> tdi.run() # doctest: +SKIP + """ + + _cmd = 'tckmap' + input_spec = ComputeTDIInputSpec + output_spec = ComputeTDIOutputSpec + + def _list_outputs(self): + outputs = self.output_spec().get() + outputs['out_file'] = op.abspath(self.inputs.out_file) + return outputs diff --git a/nipype/interfaces/semtools/diffusion/diffusion.py b/nipype/interfaces/semtools/diffusion/diffusion.py index 6140a31891..c95631ce9b 100644 --- a/nipype/interfaces/semtools/diffusion/diffusion.py +++ b/nipype/interfaces/semtools/diffusion/diffusion.py @@ -23,7 +23,7 @@ class dtiaverage(SEMLikeCommandLine): category: Diffusion.Diffusion Tensor Images.CommandLineOnly -description: dtiaverage is a program that allows to compute the average of an arbitrary number of tensor fields (listed after the --inputs option) This program is used in our pipeline as the last step of the atlas building processing. When all the tensor fields have been deformed in the same space, to create the average tensor field (--tensor_output) we use dtiaverage. +description: dtiaverage is a program that allows to compute the average of an arbitrary number of tensor fields (listed after the --inputs option) This program is used in our pipeline as the last step of the atlas building processing. When all the tensor fields have been deformed in the same space, to create the average tensor field (--tensor_output) we use dtiaverage. Several average method can be used (specified by the --method option): euclidian, log-euclidian and pga. The default being euclidian. version: 1.0.0 @@ -84,14 +84,14 @@ class dtiestim(SEMLikeCommandLine): category: Diffusion.Diffusion Weighted Images -description: dtiestim is a tool that takes in a set of DWIs (with --dwi_image option) in nrrd format and estimates a tensor field out of it. The output tensor file name is specified with the --tensor_output option -There are several methods to estimate the tensors which you can specify with the option --method lls|wls|nls|ml . Here is a short description of the different methods: +description: dtiestim is a tool that takes in a set of DWIs (with --dwi_image option) in nrrd format and estimates a tensor field out of it. The output tensor file name is specified with the --tensor_output option +There are several methods to estimate the tensors which you can specify with the option --method lls|wls|nls|ml . Here is a short description of the different methods: lls Linear least squares. Standard estimation technique that recovers the tensor parameters by multiplying the log of the normalized signal intensities by the pseudo-inverse of the gradient matrix. Default option. wls Weighted least squares. This method is similar to the linear least squares method except that the gradient matrix is weighted by the original lls estimate. (See Salvador, R., Pena, A., Menon, D. K., Carpenter, T. A., Pickard, J. D., and Bullmore, E. T. Formal characterization and extension of the linearized diffusion tensor model. Human Brain Mapping 24, 2 (Feb. 2005), 144-155. for more information on this method). This method is recommended for most applications. The weight for each iteration can be specified with the --weight_iterations. It is not currently the default due to occasional matrix singularities. - nls Non-linear least squares. This method does not take the log of the signal and requires an optimization based on levenberg-marquadt to optimize the parameters of the signal. The lls estimate is used as an initialization. For this method the step size can be specified with the --step option. + nls Non-linear least squares. This method does not take the log of the signal and requires an optimization based on levenberg-marquadt to optimize the parameters of the signal. The lls estimate is used as an initialization. For this method the step size can be specified with the --step option. ml Maximum likelihood estimation. This method is experimental and is not currently recommended. For this ml method the sigma can be specified with the option --sigma and the step size can be specified with the --step option. You can set a threshold (--threshold) to have the tensor estimated to only a subset of voxels. All the baseline voxel value higher than the threshold define the voxels where the tensors are computed. If not specified the threshold is calculated using an OTSU threshold on the baseline image.The masked generated by the -t option or by the otsu value can be saved with the --B0_mask_output option. -dtiestim also can extract a few scalar images out of the DWI set of images: +dtiestim also can extract a few scalar images out of the DWI set of images: the average baseline image (--B0) which is the average of all the B0s. the IDWI (--idwi)which is the geometric mean of the diffusion images. You can also load a mask if you want to compute the tensors only where the voxels are non-zero (--brain_mask) or a negative mask and the tensors will be estimated where the negative mask has zero values (--bad_region_mask) @@ -176,13 +176,13 @@ class dtiprocess(SEMLikeCommandLine): category: Diffusion.Diffusion Tensor Images description: dtiprocess is a tool that handles tensor fields. It takes as an input a tensor field in nrrd format. -It can generate diffusion scalar properties out of the tensor field such as : FA (--fa_output), Gradient FA image (--fa_gradient_output), color FA (--color_fa_output), MD (--md_output), Frobenius norm (--frobenius_norm_output), lbd1, lbd2, lbd3 (--lambda{1,2,3}_output), binary map of voxel where if any of the eigenvalue is negative, the voxel is set to 1 (--negative_eigenvector_output) +It can generate diffusion scalar properties out of the tensor field such as : FA (--fa_output), Gradient FA image (--fa_gradient_output), color FA (--color_fa_output), MD (--md_output), Frobenius norm (--frobenius_norm_output), lbd1, lbd2, lbd3 (--lambda{1,2,3}_output), binary map of voxel where if any of the eigenvalue is negative, the voxel is set to 1 (--negative_eigenvector_output) It also creates 4D images out of the tensor field such as: Highest eigenvector map (highest eigenvector at each voxel) (--principal_eigenvector_output) Masking capabilities: For any of the processing done with dtiprocess, it's possible to apply it on a masked region of the tensor field. You need to use the --mask option for any of the option to be applied on that tensor field sub-region only. If you want to save the masked tensor field use the option --outmask and specify the new masked tensor field file name. dtiprocess also allows a range of transformations on the tensor fields. The transformed tensor field file name is specified with the option --deformation_output. There are 3 resampling interpolation methods specified with the tag --interpolation followed by the type to use (nearestneighbor, linear, cubic) Then you have several transformations possible to apply: - - Affine transformations using as an input + - Affine transformations using as an input - itk affine transformation file (based on the itkAffineTransform class) - - Affine transformations using rview (details and download at http://www.doc.ic.ac.uk/~dr/software/). There are 2 versions of rview both creating transformation files called dof files. The old version of rview outputs text files containing the transformation parameters. It can be read in with the --dof_file option. The new version outputs binary dof files. These dof files can be transformed into human readable file with the dof2mat tool which is part of the rview package. So you need to save the output of dof2mat into a text file which can then be used with the -- newdof_file option. Usage example: dof2mat mynewdoffile.dof >> mynewdoffile.txt dtiprocess --dti_image mytensorfield.nhdr --newdof_file mynewdoffile.txt --rot_output myaffinetensorfield.nhdr + - Affine transformations using rview (details and download at http://www.doc.ic.ac.uk/~dr/software/). There are 2 versions of rview both creating transformation files called dof files. The old version of rview outputs text files containing the transformation parameters. It can be read in with the --dof_file option. The new version outputs binary dof files. These dof files can be transformed into human readable file with the dof2mat tool which is part of the rview package. So you need to save the output of dof2mat into a text file which can then be used with the -- newdof_file option. Usage example: dof2mat mynewdoffile.dof >> mynewdoffile.txt dtiprocess --dti_image mytensorfield.nhdr --newdof_file mynewdoffile.txt --rot_output myaffinetensorfield.nhdr Non linear transformations as an input: The default transformation file type is d-field (displacement field) in nrrd format. The option to use is --forward with the name of the file. If the transformation file is a h-field you have to add the option --hField. version: 1.0.1 diff --git a/nipype/interfaces/semtools/diffusion/tractography/fiberprocess.py b/nipype/interfaces/semtools/diffusion/tractography/fiberprocess.py index 7122def596..ccba1d081f 100644 --- a/nipype/interfaces/semtools/diffusion/tractography/fiberprocess.py +++ b/nipype/interfaces/semtools/diffusion/tractography/fiberprocess.py @@ -35,8 +35,8 @@ class fiberprocess(SEMLikeCommandLine): category: Diffusion.Tractography -description: fiberprocess is a tool that manage fiber files extracted from the fibertrack tool or any fiber tracking algorithm. It takes as an input .fib and .vtk files (--fiber_file) and saves the changed fibers (--fiber_output) into the 2 same formats. The main purpose of this tool is to deform the fiber file with a transformation field as an input (--displacement_field or --h_field depending if you deal with dfield or hfield). To use that option you need to specify the tensor field from which the fiber file was extracted with the option --tensor_volume. The transformation applied on the fiber file is the inverse of the one input. If the transformation is from one case to an atlas, fiberprocess assumes that the fiber file is in the atlas space and you want it in the original case space, so it's the inverse of the transformation which has been computed. -You have 2 options for fiber modification. You can either deform the fibers (their geometry) into the space OR you can keep the same geometry but map the diffusion properties (fa, md, lbd's...) of the original tensor field along the fibers at the corresponding locations. This is triggered by the --no_warp option. To use the previous example: when you have a tensor field in the original space and the deformed tensor field in the atlas space, you want to track the fibers in the atlas space, keeping this geometry but with the original case diffusion properties. Then you can specify the transformations field (from original case -> atlas) and the original tensor field with the --tensor_volume option. +description: fiberprocess is a tool that manage fiber files extracted from the fibertrack tool or any fiber tracking algorithm. It takes as an input .fib and .vtk files (--fiber_file) and saves the changed fibers (--fiber_output) into the 2 same formats. The main purpose of this tool is to deform the fiber file with a transformation field as an input (--displacement_field or --h_field depending if you deal with dfield or hfield). To use that option you need to specify the tensor field from which the fiber file was extracted with the option --tensor_volume. The transformation applied on the fiber file is the inverse of the one input. If the transformation is from one case to an atlas, fiberprocess assumes that the fiber file is in the atlas space and you want it in the original case space, so it's the inverse of the transformation which has been computed. +You have 2 options for fiber modification. You can either deform the fibers (their geometry) into the space OR you can keep the same geometry but map the diffusion properties (fa, md, lbd's...) of the original tensor field along the fibers at the corresponding locations. This is triggered by the --no_warp option. To use the previous example: when you have a tensor field in the original space and the deformed tensor field in the atlas space, you want to track the fibers in the atlas space, keeping this geometry but with the original case diffusion properties. Then you can specify the transformations field (from original case -> atlas) and the original tensor field with the --tensor_volume option. With fiberprocess you can also binarize a fiber file. Using the --voxelize option will create an image where each voxel through which a fiber is passing is set to 1. The output is going to be a binary image with the values 0 or 1 by default but the 1 value voxel can be set to any number with the --voxel_label option. Finally you can create an image where the value at the voxel is the number of fiber passing through. (--voxelize_count_fibers) version: 1.0.0 diff --git a/nipype/interfaces/semtools/diffusion/tractography/fibertrack.py b/nipype/interfaces/semtools/diffusion/tractography/fibertrack.py index 3d42620306..1599f1e30d 100644 --- a/nipype/interfaces/semtools/diffusion/tractography/fibertrack.py +++ b/nipype/interfaces/semtools/diffusion/tractography/fibertrack.py @@ -33,7 +33,7 @@ class fibertrack(SEMLikeCommandLine): category: Diffusion.Tractography description: This program implements a simple streamline tractography method based on the principal eigenvector of the tensor field. A fourth order Runge-Kutta integration rule used to advance the streamlines. -As a first parameter you have to input the tensor field (with the --input_tensor_file option). Then the region of interest image file is set with the --input_roi_file. Next you want to set the output fiber file name after the --output_fiber_file option. +As a first parameter you have to input the tensor field (with the --input_tensor_file option). Then the region of interest image file is set with the --input_roi_file. Next you want to set the output fiber file name after the --output_fiber_file option. You can specify the label value in the input_roi_file with the --target_label, --source_label and --fobidden_label options. By default target label is 1, source label is 2 and forbidden label is 0. The source label is where the streamlines are seeded, the target label defines the voxels through which the fibers must pass by to be kept in the final fiber file and the forbidden label defines the voxels where the streamlines are stopped if they pass through it. There is also a --whole_brain option which, if enabled, consider both target and source labels of the roi image as target labels and all the voxels of the image are considered as sources. During the tractography, the --fa_min parameter is used as the minimum value needed at different voxel for the tracking to keep going along a streamline. The --step_size parameter is used for each iteration of the tracking algorithm and defines the length of each step. The --max_angle option defines the maximum angle allowed between two successive segments along the tracked fiber. diff --git a/nipype/testing/data/tdi.mif b/nipype/testing/data/tdi.mif new file mode 100644 index 0000000000..e69de29bb2 diff --git a/nipype/testing/data/von-ray_errmap.nii.gz b/nipype/testing/data/von-ray_errmap.nii.gz index de7d3985d377326cb89a150464b003a61b902ddf..6cf8c2ae5ace8dc0ac25f50a89ae00b027f0acbf 100644 GIT binary patch delta 14 Vcmd1K=8*5^;8@Z>Ep#GBG5{e!1hW7D delta 14 Vcmd1K=8*5^;8=g+dB{YLWB?>|1xEk? diff --git a/nipype/testing/data/von_errmap.nii.gz b/nipype/testing/data/von_errmap.nii.gz index 8e79a46d128e3181c2aaa8c32b84fbd0902476bc..7b11981afbd7a45506afc1dadca68d7211d2d1bf 100644 GIT binary patch delta 14 VcmYdD;E?a;;8@Z>Ep#GB1OOlm1d;#% delta 14 VcmYdD;E?a;;8=g+dB{YL2mm8M1ttIh diff --git a/nipype/utils/nipype2boutiques.py b/nipype/utils/nipype2boutiques.py index 18dc9aca8e..4de41d8fb0 100644 --- a/nipype/utils/nipype2boutiques.py +++ b/nipype/utils/nipype2boutiques.py @@ -26,21 +26,21 @@ def print_inputs(tool_name, module=None, function=None): if module and function: __import__(module) interface = getattr(sys.modules[module],function)() - + inputs = interface.input_spec() outputs = interface.output_spec() - + command_line = "nipype_cmd "+str(module)+" "+tool_name+" " tool_desc = {} tool_desc['name'] = tool_name tool_desc['description'] = "Tool description goes here" - + tool_inputs = [] input_counter = 0 tool_outputs = [] - + for name, spec in sorted(interface.inputs.traits(transient=None).items()): - + input = {} input['name'] = name @@ -48,7 +48,7 @@ def print_inputs(tool_name, module=None, function=None): if "an existing file name" in type: type = "File" else: - type = "String" + type = "String" input['type'] = type input['description'] = "\n".join(interface._get_trait_desc(inputs, name, spec))[len(name)+2:].replace("\n\t\t",". ") command_line_key = "["+str(input_counter)+"_"+name.upper()+"]" @@ -58,7 +58,7 @@ def print_inputs(tool_name, module=None, function=None): if not ( hasattr(spec, "mandatory") and spec.mandatory ): input['optional'] = "true" input['command-line-flag'] = "--%s"%name+" " - + tool_inputs.append(input) command_line+= command_line_key+" " @@ -68,7 +68,7 @@ def print_inputs(tool_name, module=None, function=None): input['tempfile_name'] = tempfile_name if type == "File": setattr(interface.inputs,name,os.path.abspath(tempfile_name)) - + for name,spec in sorted(outputs.traits(transient=None).items()): output = {} @@ -85,14 +85,14 @@ def print_inputs(tool_name, module=None, function=None): if base_file_name in output_value: output_value = os.path.basename(output_value.replace(base_file_name,input['command-line-key'])) # FIXME: this only works if output is written in the current directory output['value-template'] = os.path.basename(output_value) - + output['cardinality'] = "Single" tool_outputs.append(output) # remove all temporary file names from inputs for input in tool_inputs: del input['tempfile_name'] - + tool_desc['inputs'] = tool_inputs tool_desc['outputs'] = tool_outputs tool_desc['command-line'] = command_line @@ -100,14 +100,14 @@ def print_inputs(tool_name, module=None, function=None): tool_desc['docker-index'] = 'http://index.docker.io' tool_desc['schema-version'] = '0.2-snapshot' print json.dumps(tool_desc, indent=4, separators=(',', ': ')) - + def main(argv): - + parser = argparse.ArgumentParser(description='Nipype Boutiques exporter', prog=argv[0]) parser.add_argument("module", type=str, help="Module name") parser.add_argument("interface", type=str, help="Interface name") parsed = parser.parse_args(args=argv[1:3]) - + _, prog = os.path.split(argv[0]) interface_parser = argparse.ArgumentParser(description="Run %s"%parsed.interface, prog=" ".join([prog] + argv[1:3])) print_inputs(argv[2],parsed.module, parsed.interface) diff --git a/nipype/utils/nipype_cmd.py b/nipype/utils/nipype_cmd.py index 2b514e54d8..e2ae758354 100644 --- a/nipype/utils/nipype_cmd.py +++ b/nipype/utils/nipype_cmd.py @@ -19,7 +19,7 @@ def add_options(parser=None, module=None, function=None): if parser and module and function: __import__(module) interface = getattr(sys.modules[module],function)() - + inputs = interface.input_spec() for name, spec in sorted(interface.inputs.traits(transient=None).items()): desc = "\n".join(interface._get_trait_desc(inputs, name, spec))[len(name)+2:] @@ -33,7 +33,7 @@ def add_options(parser=None, module=None, function=None): def run_instance(interface, options): if interface: print "setting function inputs" - + for input_name, _ in interface.inputs.items(): if getattr(options, input_name) != None: value = getattr(options, input_name) @@ -48,23 +48,23 @@ def run_instance(interface, options): value) except ValueError, e: print "Error when setting the value of %s: '%s'"%(input_name, str(e)) - + print interface.inputs res = interface.run() - print res.outputs + print res.outputs def main(argv): - + if len(argv) == 2 and not argv[1].startswith("-"): listClasses(argv[1]) sys.exit(0) - + parser = argparse.ArgumentParser(description='Nipype interface runner', prog=argv[0]) parser.add_argument("module", type=str, help="Module name") parser.add_argument("interface", type=str, help="Interface name") parsed = parser.parse_args(args=argv[1:3]) - + _, prog = os.path.split(argv[0]) interface_parser = argparse.ArgumentParser(description="Run %s"%parsed.interface, prog=" ".join([prog] + argv[1:3])) interface_parser, interface = add_options(interface_parser, parsed.module, parsed.interface) diff --git a/nipype/utils/tests/test_cmd.py b/nipype/utils/tests/test_cmd.py index 55347ff4b9..894569ded3 100644 --- a/nipype/utils/tests/test_cmd.py +++ b/nipype/utils/tests/test_cmd.py @@ -22,24 +22,24 @@ def test_main_returns_2_on_empty(self): with self.assertRaises(SystemExit) as cm: with capture_sys_output() as (stdout, stderr): nipype_cmd.main(['nipype_cmd']) - + exit_exception = cm.exception self.assertEqual(exit_exception.code, 2) - - self.assertEqual(stderr.getvalue(), + + self.assertEqual(stderr.getvalue(), """usage: nipype_cmd [-h] module interface nipype_cmd: error: too few arguments """) self.assertEqual(stdout.getvalue(), '') - + def test_main_returns_0_on_help(self): with self.assertRaises(SystemExit) as cm: with capture_sys_output() as (stdout, stderr): nipype_cmd.main(['nipype_cmd', '-h']) - + exit_exception = cm.exception self.assertEqual(exit_exception.code, 0) - + self.assertEqual(stderr.getvalue(), '') self.assertEqual(stdout.getvalue(), """usage: nipype_cmd [-h] module interface @@ -53,15 +53,15 @@ def test_main_returns_0_on_help(self): optional arguments: -h, --help show this help message and exit """) - + def test_list_nipy_interfacesp(self): with self.assertRaises(SystemExit) as cm: with capture_sys_output() as (stdout, stderr): nipype_cmd.main(['nipype_cmd', 'nipype.interfaces.nipy']) - + exit_exception = cm.exception self.assertEqual(exit_exception.code, 0) - + self.assertEqual(stderr.getvalue(), '') self.assertEqual(stdout.getvalue(), """Available Interfaces: @@ -77,10 +77,10 @@ def test_run_4d_realign_without_arguments(self): with self.assertRaises(SystemExit) as cm: with capture_sys_output() as (stdout, stderr): nipype_cmd.main(['nipype_cmd', 'nipype.interfaces.nipy', 'FmriRealign4d']) - + exit_exception = cm.exception self.assertEqual(exit_exception.code, 2) - + self.assertEqual(stderr.getvalue(), """usage: nipype_cmd nipype.interfaces.nipy FmriRealign4d [-h] [--between_loops BETWEEN_LOOPS] @@ -95,15 +95,15 @@ def test_run_4d_realign_without_arguments(self): nipype_cmd nipype.interfaces.nipy FmriRealign4d: error: too few arguments """) self.assertEqual(stdout.getvalue(), '') - + def test_run_4d_realign_help(self): with self.assertRaises(SystemExit) as cm: with capture_sys_output() as (stdout, stderr): nipype_cmd.main(['nipype_cmd', 'nipype.interfaces.nipy', 'FmriRealign4d', '-h']) - + exit_exception = cm.exception self.assertEqual(exit_exception.code, 0) - + self.assertEqual(stderr.getvalue(), '') self.assertTrue("Run FmriRealign4d" in stdout.getvalue()) From b7f0ea570f1ad45f6bd7985942e2f67ee9bc141c Mon Sep 17 00:00:00 2001 From: oesteban Date: Mon, 6 Jul 2015 09:07:50 +0200 Subject: [PATCH 19/29] add labelconfig interface --- nipype/interfaces/mrtrix3/__init__.py | 1 + nipype/interfaces/mrtrix3/connectivity.py | 94 +++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 nipype/interfaces/mrtrix3/connectivity.py diff --git a/nipype/interfaces/mrtrix3/__init__.py b/nipype/interfaces/mrtrix3/__init__.py index e22c4d5cec..910564f633 100644 --- a/nipype/interfaces/mrtrix3/__init__.py +++ b/nipype/interfaces/mrtrix3/__init__.py @@ -6,3 +6,4 @@ from preprocess import ResponseSD, ACTPrepareFSL from tracking import Tractography from reconst import FitTensor, EstimateFOD +from connectivity import LabelConfig diff --git a/nipype/interfaces/mrtrix3/connectivity.py b/nipype/interfaces/mrtrix3/connectivity.py new file mode 100644 index 0000000000..0d6641796b --- /dev/null +++ b/nipype/interfaces/mrtrix3/connectivity.py @@ -0,0 +1,94 @@ +# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- +# vi: set ft=python sts=4 ts=4 sw=4 et: +# -*- coding: utf-8 -*- + +""" + Change directory to provide relative paths for doctests + >>> import os + >>> filepath = os.path.dirname(os.path.realpath(__file__ )) + >>> datadir = os.path.realpath(os.path.join(filepath, + ... '../../testing/data')) + >>> os.chdir(datadir) + +""" +import os +import os.path as op + +from base import MRTrix3BaseInputSpec, MRTrix3Base +from nipype.interfaces.base import ( + CommandLineInputSpec, CommandLine, traits, TraitedSpec, File) + +from nipype.utils.filemanip import split_filename +from nipype.interfaces.traits_extension import isdefined + + +class LabelConfigInputSpec(CommandLineInputSpec): + in_file = File(exists=True, argstr='%s', mandatory=True, position=-3, + desc='input anatomical image') + in_config = File(exists=True, argstr='%s', position=-2, + desc='connectome configuration file') + out_file = File( + 'parcellation.mif', argstr='%s', mandatory=True, position=-1, + usedefault=True, desc='output file after processing') + + lut_basic = File(argstr='-lut_basic %s', desc='get information from ' + 'a basic lookup table consisting of index / name pairs') + lut_fs = File(argstr='-lut_freesurfer %s', desc='get information from ' + 'a FreeSurfer lookup table(typically "FreeSurferColorLUT' + '.txt")') + lut_aal = File(argstr='-lut_aal %s', desc='get information from the AAL ' + 'lookup table (typically "ROI_MNI_V4.txt")') + lut_itksnap = File(argstr='-lut_itksnap %s', desc='get information from an' + ' ITK - SNAP lookup table(this includes the IIT atlas ' + 'file "LUT_GM.txt")') + spine = File(argstr='-spine %s', desc='provide a manually-defined ' + 'segmentation of the base of the spine where the streamlines' + ' terminate, so that this can become a node in the connection' + ' matrix.') + nthreads = traits.Int( + argstr='-nthreads %d', desc='number of threads. if zero, the number' + ' of available cpus will be used') + + +class LabelConfigOutputSpec(TraitedSpec): + out_file = File(exists=True, desc='the output response file') + + +class LabelConfig(MRTrix3Base): + + """ + Generate anatomical information necessary for Anatomically + Constrained Tractography (ACT). + + Example + ------- + + >>> import nipype.interfaces.mrtrix3 as mrt + >>> labels = mrt.LabelConfig() + >>> labels.inputs.in_file = 'aparc+aseg.nii.gz' + >>> labels.inputs.in_config = 'mrtrix3_labelconfig.txt' + >>> labels.cmdline # doctest: +ELLIPSIS + 'labelconfig aparc+aseg.nii.gz mrtrix3_labelconfig.txt parcellation.mif' + >>> labels.run() # doctest: +SKIP + """ + + _cmd = 'labelconfig:' + input_spec = LabelConfigInputSpec + output_spec = LabelConfigOutputSpec + + def _parse_inputs(self, skip=None): + if skip is None: + skip = [] + + if not isdefined(self.inputs.in_config): + from distutils.spawn import find_executable + path = op.dirname(find_executable(self._cmd)) + self.inputs.in_config = op.abspath( + op.join(path, '../src/dwi/tractography/connectomics/' + 'example_configs/fs_default.txt')) + return super(LabelConfig, self)._parse_inputs(skip=skip) + + def _list_outputs(self): + outputs = self.output_spec().get() + outputs['out_file'] = op.abspath(self.inputs.out_file) + return outputs From 50168f55c92670f5609c67449ea688d13c040a90 Mon Sep 17 00:00:00 2001 From: oesteban Date: Mon, 6 Jul 2015 09:22:09 +0200 Subject: [PATCH 20/29] fix default file finding --- nipype/interfaces/mrtrix3/connectivity.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/nipype/interfaces/mrtrix3/connectivity.py b/nipype/interfaces/mrtrix3/connectivity.py index 0d6641796b..47e1539561 100644 --- a/nipype/interfaces/mrtrix3/connectivity.py +++ b/nipype/interfaces/mrtrix3/connectivity.py @@ -72,7 +72,7 @@ class LabelConfig(MRTrix3Base): >>> labels.run() # doctest: +SKIP """ - _cmd = 'labelconfig:' + _cmd = 'labelconfig' input_spec = LabelConfigInputSpec output_spec = LabelConfigOutputSpec @@ -82,10 +82,16 @@ def _parse_inputs(self, skip=None): if not isdefined(self.inputs.in_config): from distutils.spawn import find_executable - path = op.dirname(find_executable(self._cmd)) - self.inputs.in_config = op.abspath( - op.join(path, '../src/dwi/tractography/connectomics/' - 'example_configs/fs_default.txt')) + path = find_executable(self._cmd) + if path is None: + path = os.getenv(MRTRIX3_HOME, '/opt/mrtrix3') + else: + path = op.dirname(op.dirname(path)) + + self.inputs.in_config = op.join( + path, 'src/dwi/tractography/connectomics/' + 'example_configs/fs_default.txt') + return super(LabelConfig, self)._parse_inputs(skip=skip) def _list_outputs(self): From 3e326f1dccce579b63eb89271ed85659039d9114 Mon Sep 17 00:00:00 2001 From: oesteban Date: Mon, 6 Jul 2015 09:43:44 +0200 Subject: [PATCH 21/29] add interface for fs_parc_replace_sgm_first --- nipype/interfaces/mrtrix3/__init__.py | 2 +- nipype/interfaces/mrtrix3/connectivity.py | 3 +- nipype/interfaces/mrtrix3/preprocess.py | 47 +++++++++++++++++++++ nipype/testing/data/mrtrix3_labelconfig.txt | 0 4 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 nipype/testing/data/mrtrix3_labelconfig.txt diff --git a/nipype/interfaces/mrtrix3/__init__.py b/nipype/interfaces/mrtrix3/__init__.py index 910564f633..b673613fd1 100644 --- a/nipype/interfaces/mrtrix3/__init__.py +++ b/nipype/interfaces/mrtrix3/__init__.py @@ -3,7 +3,7 @@ # -*- coding: utf-8 -*- from utils import Mesh2PVE, Generate5tt, BrainMask, TensorMetrics, ComputeTDI -from preprocess import ResponseSD, ACTPrepareFSL +from preprocess import ResponseSD, ACTPrepareFSL, ReplaceFSwithFIRST from tracking import Tractography from reconst import FitTensor, EstimateFOD from connectivity import LabelConfig diff --git a/nipype/interfaces/mrtrix3/connectivity.py b/nipype/interfaces/mrtrix3/connectivity.py index 47e1539561..ee951b9de3 100644 --- a/nipype/interfaces/mrtrix3/connectivity.py +++ b/nipype/interfaces/mrtrix3/connectivity.py @@ -57,8 +57,7 @@ class LabelConfigOutputSpec(TraitedSpec): class LabelConfig(MRTrix3Base): """ - Generate anatomical information necessary for Anatomically - Constrained Tractography (ACT). + Re-configure parcellation to be incrementally defined. Example ------- diff --git a/nipype/interfaces/mrtrix3/preprocess.py b/nipype/interfaces/mrtrix3/preprocess.py index a853065fdf..80bac949f1 100644 --- a/nipype/interfaces/mrtrix3/preprocess.py +++ b/nipype/interfaces/mrtrix3/preprocess.py @@ -153,3 +153,50 @@ def _list_outputs(self): outputs = self.output_spec().get() outputs['out_file'] = op.abspath(self.inputs.out_file) return outputs + + +class ReplaceFSwithFIRSTInputSpec(CommandLineInputSpec): + in_file = File(exists=True, argstr='%s', mandatory=True, position=-4, + desc='input anatomical image') + in_t1w = File(exists=True, argstr='%s', mandatory=True, position=-3, + desc='input T1 image') + in_config = File(exists=True, argstr='%s', position=-2, + desc='connectome configuration file') + + out_file = File( + 'aparc+first.mif', argstr='%s', mandatory=True, position=-1, + usedefault=True, desc='output file after processing') + + +class ReplaceFSwithFIRSTOutputSpec(TraitedSpec): + out_file = File(exists=True, desc='the output response file') + + +class ReplaceFSwithFIRST(CommandLine): + + """ + Replace deep gray matter structures segmented with FSL FIRST in a + FreeSurfer parcellation. + + Example + ------- + + >>> import nipype.interfaces.mrtrix3 as mrt + >>> prep = mrt.ReplaceFSwithFIRST() + >>> prep.inputs.in_file = 'aparc+aseg.nii.gz' + >>> prep.inputs.in_t1w = 'T1.nii.gz' + >>> prep.inputs.in_config = 'mrtrix3_labelconfig.txt' + >>> prep.cmdline # doctest: +ELLIPSIS + 'fs_parc_replace_sgm_first aparc+aseg.nii.gz T1.nii.gz \ +mrtrix3_labelconfig.txt aparc+first.mif' + >>> prep.run() # doctest: +SKIP + """ + + _cmd = 'fs_parc_replace_sgm_first' + input_spec = ReplaceFSwithFIRSTInputSpec + output_spec = ReplaceFSwithFIRSTOutputSpec + + def _list_outputs(self): + outputs = self.output_spec().get() + outputs['out_file'] = op.abspath(self.inputs.out_file) + return outputs diff --git a/nipype/testing/data/mrtrix3_labelconfig.txt b/nipype/testing/data/mrtrix3_labelconfig.txt new file mode 100644 index 0000000000..e69de29bb2 From f03d224dadfc8b5718dc14654f7dda22314dc677 Mon Sep 17 00:00:00 2001 From: oesteban Date: Mon, 6 Jul 2015 10:02:31 +0200 Subject: [PATCH 22/29] add tck2connectome interface --- nipype/interfaces/mrtrix3/__init__.py | 2 +- nipype/interfaces/mrtrix3/connectivity.py | 108 ++++++++++++++++++++++ 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/nipype/interfaces/mrtrix3/__init__.py b/nipype/interfaces/mrtrix3/__init__.py index b673613fd1..7dd58800c1 100644 --- a/nipype/interfaces/mrtrix3/__init__.py +++ b/nipype/interfaces/mrtrix3/__init__.py @@ -6,4 +6,4 @@ from preprocess import ResponseSD, ACTPrepareFSL, ReplaceFSwithFIRST from tracking import Tractography from reconst import FitTensor, EstimateFOD -from connectivity import LabelConfig +from connectivity import LabelConfig, BuildConnectome diff --git a/nipype/interfaces/mrtrix3/connectivity.py b/nipype/interfaces/mrtrix3/connectivity.py index ee951b9de3..d45d1d6492 100644 --- a/nipype/interfaces/mrtrix3/connectivity.py +++ b/nipype/interfaces/mrtrix3/connectivity.py @@ -22,6 +22,114 @@ from nipype.interfaces.traits_extension import isdefined +class BuildConnectomeInputSpec(CommandLineInputSpec): + in_file = File(exists=True, argstr='%s', mandatory=True, position=-3, + desc='input tractography') + in_parc = File(exists=True, argstr='%s', position=-2, + desc='parcellation file') + out_file = File( + 'connectome.csv', argstr='%s', mandatory=True, position=-1, + usedefault=True, desc='output file after processing') + + nthreads = traits.Int( + argstr='-nthreads %d', desc='number of threads. if zero, the number' + ' of available cpus will be used') + + vox_lookup = traits.Bool( + argstr='-assignment_voxel_lookup', + desc='use a simple voxel lookup value at each streamline endpoint') + search_radius = traits.Float( + argstr='-assignment_radial_search %f', + desc='perform a radial search from each streamline endpoint to locate ' + 'the nearest node. Argument is the maximum radius in mm; if no node is' + ' found within this radius, the streamline endpoint is not assigned to' + ' any node.') + search_reverse = traits.Float( + argstr='-assignment_reverse_search %f', + desc='traverse from each streamline endpoint inwards along the ' + 'streamline, in search of the last node traversed by the streamline. ' + 'Argument is the maximum traversal length in mm (set to 0 to allow ' + 'search to continue to the streamline midpoint).') + search_forward = traits.Float( + argstr='-assignment_forward_search %f', + desc='project the streamline forwards from the endpoint in search of a' + 'parcellation node voxel. Argument is the maximum traversal length in ' + 'mm.') + + metric = traits.Enum( + 'count', 'meanlength', 'invlength', 'invnodevolume', 'mean_scalar', + 'invlength_invnodevolume', argstr='-metric %s', desc='specify the edge' + ' weight metric') + + in_scalar = File( + exists=True, argstr='-image %s', desc='provide the associated image ' + 'for the mean_scalar metric') + + in_weights = File( + exists=True, argstr='-tck_weights_in %s', desc='specify a text scalar ' + 'file containing the streamline weights') + + keep_unassigned = traits.Bool( + argstr='-keep_unassigned', desc='By default, the program discards the' + ' information regarding those streamlines that are not successfully ' + 'assigned to a node pair. Set this option to keep these values (will ' + 'be the first row/column in the output matrix)') + zero_diagonal = traits.Bool( + argstr='-zero_diagonal', desc='set all diagonal entries in the matrix ' + 'to zero (these represent streamlines that connect to the same node at' + ' both ends)') + + +class BuildConnectomeOutputSpec(TraitedSpec): + out_file = File(exists=True, desc='the output response file') + + +class BuildConnectome(MRTrix3Base): + + """ + Generate a connectome matrix from a streamlines file and a node + parcellation image + + Example + ------- + + >>> import nipype.interfaces.mrtrix3 as mrt + >>> mat = mrt.BuildConnectome() + >>> mat.inputs.in_file = 'aparc+aseg.nii.gz' + >>> mat.inputs.in_config = 'mrtrix3_labelconfig.txt' + >>> mat.cmdline # doctest: +ELLIPSIS + 'labelconfig aparc+aseg.nii.gz mrtrix3_labelconfig.txt parcellation.mif' + >>> mat.run() # doctest: +SKIP + """ + + _cmd = 'labelconfig' + input_spec = BuildConnectomeInputSpec + output_spec = BuildConnectomeOutputSpec + + def _parse_inputs(self, skip=None): + if skip is None: + skip = [] + + if not isdefined(self.inputs.in_config): + from distutils.spawn import find_executable + path = find_executable(self._cmd) + if path is None: + path = os.getenv(MRTRIX3_HOME, '/opt/mrtrix3') + else: + path = op.dirname(op.dirname(path)) + + self.inputs.in_config = op.join( + path, 'src/dwi/tractography/connectomics/' + 'example_configs/fs_default.txt') + + return super(BuildConnectome, self)._parse_inputs(skip=skip) + + def _list_outputs(self): + outputs = self.output_spec().get() + outputs['out_file'] = op.abspath(self.inputs.out_file) + return outputs + + class LabelConfigInputSpec(CommandLineInputSpec): in_file = File(exists=True, argstr='%s', mandatory=True, position=-3, desc='input anatomical image') From a27a416d9e79171feda3cbe94466bbe3a2c45a83 Mon Sep 17 00:00:00 2001 From: oesteban Date: Mon, 6 Jul 2015 10:16:45 +0200 Subject: [PATCH 23/29] fix errors and missing parts --- nipype/interfaces/mrtrix3/connectivity.py | 26 ++++------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/nipype/interfaces/mrtrix3/connectivity.py b/nipype/interfaces/mrtrix3/connectivity.py index d45d1d6492..4d128bce05 100644 --- a/nipype/interfaces/mrtrix3/connectivity.py +++ b/nipype/interfaces/mrtrix3/connectivity.py @@ -95,35 +95,17 @@ class BuildConnectome(MRTrix3Base): >>> import nipype.interfaces.mrtrix3 as mrt >>> mat = mrt.BuildConnectome() - >>> mat.inputs.in_file = 'aparc+aseg.nii.gz' - >>> mat.inputs.in_config = 'mrtrix3_labelconfig.txt' + >>> mat.inputs.in_file = 'tracked.tck' + >>> mat.inputs.in_parc = 'aparc+aseg.nii.gz' >>> mat.cmdline # doctest: +ELLIPSIS - 'labelconfig aparc+aseg.nii.gz mrtrix3_labelconfig.txt parcellation.mif' + 'tck2connectome tracked.tck aparc+aseg.nii.gz connectome.csv' >>> mat.run() # doctest: +SKIP """ - _cmd = 'labelconfig' + _cmd = 'tck2connectome' input_spec = BuildConnectomeInputSpec output_spec = BuildConnectomeOutputSpec - def _parse_inputs(self, skip=None): - if skip is None: - skip = [] - - if not isdefined(self.inputs.in_config): - from distutils.spawn import find_executable - path = find_executable(self._cmd) - if path is None: - path = os.getenv(MRTRIX3_HOME, '/opt/mrtrix3') - else: - path = op.dirname(op.dirname(path)) - - self.inputs.in_config = op.join( - path, 'src/dwi/tractography/connectomics/' - 'example_configs/fs_default.txt') - - return super(BuildConnectome, self)._parse_inputs(skip=skip) - def _list_outputs(self): outputs = self.output_spec().get() outputs['out_file'] = op.abspath(self.inputs.out_file) From 9d298b206825930ffb78a3899731dac4331897ec Mon Sep 17 00:00:00 2001 From: oesteban Date: Mon, 6 Jul 2015 11:42:47 +0200 Subject: [PATCH 24/29] add auto tests, fix doctests --- nipype/interfaces/mrtrix3/connectivity.py | 10 +-- nipype/interfaces/mrtrix3/preprocess.py | 4 +- .../tests/test_auto_BuildConnectome.py | 63 +++++++++++++++++++ .../mrtrix3/tests/test_auto_LabelConfig.py | 55 ++++++++++++++++ .../tests/test_auto_ReplaceFSwithFIRST.py | 47 ++++++++++++++ 5 files changed, 172 insertions(+), 7 deletions(-) create mode 100644 nipype/interfaces/mrtrix3/tests/test_auto_BuildConnectome.py create mode 100644 nipype/interfaces/mrtrix3/tests/test_auto_LabelConfig.py create mode 100644 nipype/interfaces/mrtrix3/tests/test_auto_ReplaceFSwithFIRST.py diff --git a/nipype/interfaces/mrtrix3/connectivity.py b/nipype/interfaces/mrtrix3/connectivity.py index 4d128bce05..347f45691b 100644 --- a/nipype/interfaces/mrtrix3/connectivity.py +++ b/nipype/interfaces/mrtrix3/connectivity.py @@ -95,10 +95,10 @@ class BuildConnectome(MRTrix3Base): >>> import nipype.interfaces.mrtrix3 as mrt >>> mat = mrt.BuildConnectome() - >>> mat.inputs.in_file = 'tracked.tck' - >>> mat.inputs.in_parc = 'aparc+aseg.nii.gz' + >>> mat.inputs.in_file = 'tracks.tck' + >>> mat.inputs.in_parc = 'aparc+aseg.nii' >>> mat.cmdline # doctest: +ELLIPSIS - 'tck2connectome tracked.tck aparc+aseg.nii.gz connectome.csv' + 'tck2connectome tracks.tck aparc+aseg.nii connectome.csv' >>> mat.run() # doctest: +SKIP """ @@ -154,10 +154,10 @@ class LabelConfig(MRTrix3Base): >>> import nipype.interfaces.mrtrix3 as mrt >>> labels = mrt.LabelConfig() - >>> labels.inputs.in_file = 'aparc+aseg.nii.gz' + >>> labels.inputs.in_file = 'aparc+aseg.nii' >>> labels.inputs.in_config = 'mrtrix3_labelconfig.txt' >>> labels.cmdline # doctest: +ELLIPSIS - 'labelconfig aparc+aseg.nii.gz mrtrix3_labelconfig.txt parcellation.mif' + 'labelconfig aparc+aseg.nii mrtrix3_labelconfig.txt parcellation.mif' >>> labels.run() # doctest: +SKIP """ diff --git a/nipype/interfaces/mrtrix3/preprocess.py b/nipype/interfaces/mrtrix3/preprocess.py index 80bac949f1..aea3ef97f9 100644 --- a/nipype/interfaces/mrtrix3/preprocess.py +++ b/nipype/interfaces/mrtrix3/preprocess.py @@ -183,11 +183,11 @@ class ReplaceFSwithFIRST(CommandLine): >>> import nipype.interfaces.mrtrix3 as mrt >>> prep = mrt.ReplaceFSwithFIRST() - >>> prep.inputs.in_file = 'aparc+aseg.nii.gz' + >>> prep.inputs.in_file = 'aparc+aseg.nii' >>> prep.inputs.in_t1w = 'T1.nii.gz' >>> prep.inputs.in_config = 'mrtrix3_labelconfig.txt' >>> prep.cmdline # doctest: +ELLIPSIS - 'fs_parc_replace_sgm_first aparc+aseg.nii.gz T1.nii.gz \ + 'fs_parc_replace_sgm_first aparc+aseg.nii T1.nii.gz \ mrtrix3_labelconfig.txt aparc+first.mif' >>> prep.run() # doctest: +SKIP """ diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_BuildConnectome.py b/nipype/interfaces/mrtrix3/tests/test_auto_BuildConnectome.py new file mode 100644 index 0000000000..f31704ae9a --- /dev/null +++ b/nipype/interfaces/mrtrix3/tests/test_auto_BuildConnectome.py @@ -0,0 +1,63 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from nipype.testing import assert_equal +from nipype.interfaces.mrtrix3.connectivity import BuildConnectome + +def test_BuildConnectome_inputs(): + input_map = dict(args=dict(argstr='%s', + ), + environ=dict(nohash=True, + usedefault=True, + ), + ignore_exception=dict(nohash=True, + usedefault=True, + ), + in_file=dict(argstr='%s', + mandatory=True, + position=-3, + ), + in_parc=dict(argstr='%s', + position=-2, + ), + in_scalar=dict(argstr='-image %s', + ), + in_weights=dict(argstr='-tck_weights_in %s', + ), + keep_unassigned=dict(argstr='-keep_unassigned', + ), + metric=dict(argstr='-metric %s', + ), + nthreads=dict(argstr='-nthreads %d', + ), + out_file=dict(argstr='%s', + mandatory=True, + position=-1, + usedefault=True, + ), + search_forward=dict(argstr='-assignment_forward_search %f', + ), + search_radius=dict(argstr='-assignment_radial_search %f', + ), + search_reverse=dict(argstr='-assignment_reverse_search %f', + ), + terminal_output=dict(nohash=True, + ), + vox_lookup=dict(argstr='-assignment_voxel_lookup', + ), + zero_diagonal=dict(argstr='-zero_diagonal', + ), + ) + inputs = BuildConnectome.input_spec() + + for key, metadata in input_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(inputs.traits()[key], metakey), value + +def test_BuildConnectome_outputs(): + output_map = dict(out_file=dict(), + ) + outputs = BuildConnectome.output_spec() + + for key, metadata in output_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(outputs.traits()[key], metakey), value + diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_LabelConfig.py b/nipype/interfaces/mrtrix3/tests/test_auto_LabelConfig.py new file mode 100644 index 0000000000..e7cb7c62eb --- /dev/null +++ b/nipype/interfaces/mrtrix3/tests/test_auto_LabelConfig.py @@ -0,0 +1,55 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from nipype.testing import assert_equal +from nipype.interfaces.mrtrix3.connectivity import LabelConfig + +def test_LabelConfig_inputs(): + input_map = dict(args=dict(argstr='%s', + ), + environ=dict(nohash=True, + usedefault=True, + ), + ignore_exception=dict(nohash=True, + usedefault=True, + ), + in_config=dict(argstr='%s', + position=-2, + ), + in_file=dict(argstr='%s', + mandatory=True, + position=-3, + ), + lut_aal=dict(argstr='-lut_aal %s', + ), + lut_basic=dict(argstr='-lut_basic %s', + ), + lut_fs=dict(argstr='-lut_freesurfer %s', + ), + lut_itksnap=dict(argstr='-lut_itksnap %s', + ), + nthreads=dict(argstr='-nthreads %d', + ), + out_file=dict(argstr='%s', + mandatory=True, + position=-1, + usedefault=True, + ), + spine=dict(argstr='-spine %s', + ), + terminal_output=dict(nohash=True, + ), + ) + inputs = LabelConfig.input_spec() + + for key, metadata in input_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(inputs.traits()[key], metakey), value + +def test_LabelConfig_outputs(): + output_map = dict(out_file=dict(), + ) + outputs = LabelConfig.output_spec() + + for key, metadata in output_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(outputs.traits()[key], metakey), value + diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_ReplaceFSwithFIRST.py b/nipype/interfaces/mrtrix3/tests/test_auto_ReplaceFSwithFIRST.py new file mode 100644 index 0000000000..fd5b38bc42 --- /dev/null +++ b/nipype/interfaces/mrtrix3/tests/test_auto_ReplaceFSwithFIRST.py @@ -0,0 +1,47 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from nipype.testing import assert_equal +from nipype.interfaces.mrtrix3.preprocess import ReplaceFSwithFIRST + +def test_ReplaceFSwithFIRST_inputs(): + input_map = dict(args=dict(argstr='%s', + ), + environ=dict(nohash=True, + usedefault=True, + ), + ignore_exception=dict(nohash=True, + usedefault=True, + ), + in_config=dict(argstr='%s', + position=-2, + ), + in_file=dict(argstr='%s', + mandatory=True, + position=-4, + ), + in_t1w=dict(argstr='%s', + mandatory=True, + position=-3, + ), + out_file=dict(argstr='%s', + mandatory=True, + position=-1, + usedefault=True, + ), + terminal_output=dict(nohash=True, + ), + ) + inputs = ReplaceFSwithFIRST.input_spec() + + for key, metadata in input_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(inputs.traits()[key], metakey), value + +def test_ReplaceFSwithFIRST_outputs(): + output_map = dict(out_file=dict(), + ) + outputs = ReplaceFSwithFIRST.output_spec() + + for key, metadata in output_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(outputs.traits()[key], metakey), value + From 9709872f3ea049852737635990b70b45d3e536cd Mon Sep 17 00:00:00 2001 From: oesteban Date: Fri, 10 Jul 2015 07:54:37 +0200 Subject: [PATCH 25/29] add nohash=True on nthreads option --- nipype/interfaces/mrtrix3/base.py | 2 +- nipype/interfaces/mrtrix3/connectivity.py | 4 ++-- nipype/interfaces/mrtrix3/tests/test_auto_BrainMask.py | 1 + nipype/interfaces/mrtrix3/tests/test_auto_BuildConnectome.py | 1 + nipype/interfaces/mrtrix3/tests/test_auto_ComputeTDI.py | 1 + nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py | 1 + nipype/interfaces/mrtrix3/tests/test_auto_FitTensor.py | 1 + nipype/interfaces/mrtrix3/tests/test_auto_LabelConfig.py | 1 + nipype/interfaces/mrtrix3/tests/test_auto_ResponseSD.py | 1 + nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py | 1 + nipype/interfaces/mrtrix3/utils.py | 2 +- 11 files changed, 12 insertions(+), 4 deletions(-) diff --git a/nipype/interfaces/mrtrix3/base.py b/nipype/interfaces/mrtrix3/base.py index b1a6aea524..1c6afdf13e 100644 --- a/nipype/interfaces/mrtrix3/base.py +++ b/nipype/interfaces/mrtrix3/base.py @@ -28,7 +28,7 @@ class MRTrix3BaseInputSpec(CommandLineInputSpec): nthreads = traits.Int( argstr='-nthreads %d', desc='number of threads. if zero, the number' - ' of available cpus will be used') + ' of available cpus will be used', nohash=True) # DW gradient table import options grad_file = File(exists=True, argstr='-grad %s', desc='dw gradient scheme (MRTrix format') diff --git a/nipype/interfaces/mrtrix3/connectivity.py b/nipype/interfaces/mrtrix3/connectivity.py index 347f45691b..af09ae36bc 100644 --- a/nipype/interfaces/mrtrix3/connectivity.py +++ b/nipype/interfaces/mrtrix3/connectivity.py @@ -33,7 +33,7 @@ class BuildConnectomeInputSpec(CommandLineInputSpec): nthreads = traits.Int( argstr='-nthreads %d', desc='number of threads. if zero, the number' - ' of available cpus will be used') + ' of available cpus will be used', nohash=True) vox_lookup = traits.Bool( argstr='-assignment_voxel_lookup', @@ -137,7 +137,7 @@ class LabelConfigInputSpec(CommandLineInputSpec): ' matrix.') nthreads = traits.Int( argstr='-nthreads %d', desc='number of threads. if zero, the number' - ' of available cpus will be used') + ' of available cpus will be used', nohash=True) class LabelConfigOutputSpec(TraitedSpec): diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_BrainMask.py b/nipype/interfaces/mrtrix3/tests/test_auto_BrainMask.py index f230719694..0567f8b9ab 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_BrainMask.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_BrainMask.py @@ -22,6 +22,7 @@ def test_BrainMask_inputs(): position=-2, ), nthreads=dict(argstr='-nthreads %d', + nohash=True, ), out_file=dict(argstr='%s', mandatory=True, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_BuildConnectome.py b/nipype/interfaces/mrtrix3/tests/test_auto_BuildConnectome.py index f31704ae9a..68ea51ede8 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_BuildConnectome.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_BuildConnectome.py @@ -27,6 +27,7 @@ def test_BuildConnectome_inputs(): metric=dict(argstr='-metric %s', ), nthreads=dict(argstr='-nthreads %d', + nohash=True, ), out_file=dict(argstr='%s', mandatory=True, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_ComputeTDI.py b/nipype/interfaces/mrtrix3/tests/test_auto_ComputeTDI.py index 8f6a1122fa..25c36d0265 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_ComputeTDI.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_ComputeTDI.py @@ -32,6 +32,7 @@ def test_ComputeTDI_inputs(): max_tod=dict(argstr='-tod %d', ), nthreads=dict(argstr='-nthreads %d', + nohash=True, ), out_file=dict(argstr='%s', position=-1, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py b/nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py index 809685b752..e01c948b8f 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py @@ -32,6 +32,7 @@ def test_EstimateFOD_inputs(): neg_lambda=dict(argstr='-neg_lambda %f', ), nthreads=dict(argstr='-nthreads %d', + nohash=True, ), out_file=dict(argstr='%s', mandatory=True, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_FitTensor.py b/nipype/interfaces/mrtrix3/tests/test_auto_FitTensor.py index 1c7a31e78a..410e9a58b1 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_FitTensor.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_FitTensor.py @@ -26,6 +26,7 @@ def test_FitTensor_inputs(): method=dict(argstr='-method %s', ), nthreads=dict(argstr='-nthreads %d', + nohash=True, ), out_file=dict(argstr='%s', mandatory=True, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_LabelConfig.py b/nipype/interfaces/mrtrix3/tests/test_auto_LabelConfig.py index e7cb7c62eb..f559920ab1 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_LabelConfig.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_LabelConfig.py @@ -27,6 +27,7 @@ def test_LabelConfig_inputs(): lut_itksnap=dict(argstr='-lut_itksnap %s', ), nthreads=dict(argstr='-nthreads %d', + nohash=True, ), out_file=dict(argstr='%s', mandatory=True, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_ResponseSD.py b/nipype/interfaces/mrtrix3/tests/test_auto_ResponseSD.py index c1e1b6094e..68cabe4fca 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_ResponseSD.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_ResponseSD.py @@ -34,6 +34,7 @@ def test_ResponseSD_inputs(): max_sh=dict(argstr='-lmax %d', ), nthreads=dict(argstr='-nthreads %d', + nohash=True, ), out_file=dict(argstr='%s', mandatory=True, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py b/nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py index 0d64f9e6c5..5b98797a4e 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py @@ -57,6 +57,7 @@ def test_Tractography_inputs(): noprecompt=dict(argstr='-noprecomputed', ), nthreads=dict(argstr='-nthreads %d', + nohash=True, ), out_file=dict(argstr='%s', mandatory=True, diff --git a/nipype/interfaces/mrtrix3/utils.py b/nipype/interfaces/mrtrix3/utils.py index 79e3cee072..89a3ccfacf 100644 --- a/nipype/interfaces/mrtrix3/utils.py +++ b/nipype/interfaces/mrtrix3/utils.py @@ -281,7 +281,7 @@ class ComputeTDIInputSpec(CommandLineInputSpec): ' a text scalar file containing the streamline weights') nthreads = traits.Int( argstr='-nthreads %d', desc='number of threads. if zero, the number' - ' of available cpus will be used') + ' of available cpus will be used', nohash=True) class ComputeTDIOutputSpec(TraitedSpec): From 8ba033c34a43e556c5efabe2aab1f90091e97310 Mon Sep 17 00:00:00 2001 From: oesteban Date: Fri, 10 Jul 2015 08:11:25 +0200 Subject: [PATCH 26/29] add tck2vtk --- nipype/interfaces/mrtrix3/__init__.py | 3 +- .../mrtrix3/tests/test_auto_TCK2VTK.py | 46 +++++++++++++++++ nipype/interfaces/mrtrix3/utils.py | 50 +++++++++++++++++++ 3 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 nipype/interfaces/mrtrix3/tests/test_auto_TCK2VTK.py diff --git a/nipype/interfaces/mrtrix3/__init__.py b/nipype/interfaces/mrtrix3/__init__.py index 7dd58800c1..ec7d02aecb 100644 --- a/nipype/interfaces/mrtrix3/__init__.py +++ b/nipype/interfaces/mrtrix3/__init__.py @@ -2,7 +2,8 @@ # vi: set ft=python sts=4 ts=4 sw=4 et: # -*- coding: utf-8 -*- -from utils import Mesh2PVE, Generate5tt, BrainMask, TensorMetrics, ComputeTDI +from utils import (Mesh2PVE, Generate5tt, BrainMask, TensorMetrics, + ComputeTDI, TCK2VTK) from preprocess import ResponseSD, ACTPrepareFSL, ReplaceFSwithFIRST from tracking import Tractography from reconst import FitTensor, EstimateFOD diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_TCK2VTK.py b/nipype/interfaces/mrtrix3/tests/test_auto_TCK2VTK.py new file mode 100644 index 0000000000..6e7c5c193f --- /dev/null +++ b/nipype/interfaces/mrtrix3/tests/test_auto_TCK2VTK.py @@ -0,0 +1,46 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from nipype.testing import assert_equal +from nipype.interfaces.mrtrix3.utils import TCK2VTK + +def test_TCK2VTK_inputs(): + input_map = dict(args=dict(argstr='%s', + ), + environ=dict(nohash=True, + usedefault=True, + ), + ignore_exception=dict(nohash=True, + usedefault=True, + ), + in_file=dict(argstr='%s', + mandatory=True, + position=-2, + ), + nthreads=dict(argstr='-nthreads %d', + nohash=True, + ), + out_file=dict(argstr='%s', + position=-1, + usedefault=True, + ), + reference=dict(argstr='-image %s', + ), + terminal_output=dict(nohash=True, + ), + voxel=dict(argstr='-image %s', + ), + ) + inputs = TCK2VTK.input_spec() + + for key, metadata in input_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(inputs.traits()[key], metakey), value + +def test_TCK2VTK_outputs(): + output_map = dict(out_file=dict(), + ) + outputs = TCK2VTK.output_spec() + + for key, metadata in output_map.items(): + for metakey, value in metadata.items(): + yield assert_equal, getattr(outputs.traits()[key], metakey), value + diff --git a/nipype/interfaces/mrtrix3/utils.py b/nipype/interfaces/mrtrix3/utils.py index 89a3ccfacf..220b7024dc 100644 --- a/nipype/interfaces/mrtrix3/utils.py +++ b/nipype/interfaces/mrtrix3/utils.py @@ -351,3 +351,53 @@ def _list_outputs(self): outputs = self.output_spec().get() outputs['out_file'] = op.abspath(self.inputs.out_file) return outputs + + +class TCK2VTKInputSpec(CommandLineInputSpec): + in_file = File(exists=True, argstr='%s', mandatory=True, position=-2, + desc='input tractography') + out_file = File('tracked.vtk', argstr='%s', usedefault=True, position=-1, + desc='output VTK file') + reference = File( + exists=True, argstr='-image %s', desc='if specified, the properties of' + ' this image will be used to convert track point positions from real ' + '(scanner) coordinates into image coordinates (in mm).') + voxel = File( + exists=True, argstr='-image %s', desc='if specified, the properties of' + ' this image will be used to convert track point positions from real ' + '(scanner) coordinates into image coordinates.') + + nthreads = traits.Int( + argstr='-nthreads %d', desc='number of threads. if zero, the number' + ' of available cpus will be used', nohash=True) + + +class TCK2VTKOutputSpec(TraitedSpec): + out_file = File(desc='output VTK file') + + +class TCK2VTK(MRTrix3Base): + + """ + + + Example + ------- + + >>> import nipype.interfaces.mrtrix3 as mrt + >>> vtk = mrt.TCK2VTK() + >>> vtk.inputs.in_file = 'tracked.tck' + >>> vtk.inputs.reference = 'dwi.nii.gz' + >>> vtk.cmdline # doctest: +ELLIPSIS + 'tck2vtk -image dwi.nii.gz tracked.tck tracked.vtk' + >>> vtk.run() # doctest: +SKIP + """ + + _cmd = 'tck2vtk' + input_spec = TCK2VTKInputSpec + output_spec = TCK2VTKOutputSpec + + def _list_outputs(self): + outputs = self.output_spec().get() + outputs['out_file'] = op.abspath(self.inputs.out_file) + return outputs From 9c5eaddad75129c1993d08b09713690ca4ce0c50 Mon Sep 17 00:00:00 2001 From: oesteban Date: Fri, 10 Jul 2015 08:29:25 +0200 Subject: [PATCH 27/29] fix doctests --- nipype/interfaces/mrtrix3/utils.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/nipype/interfaces/mrtrix3/utils.py b/nipype/interfaces/mrtrix3/utils.py index 220b7024dc..fe542f8000 100644 --- a/nipype/interfaces/mrtrix3/utils.py +++ b/nipype/interfaces/mrtrix3/utils.py @@ -356,7 +356,7 @@ def _list_outputs(self): class TCK2VTKInputSpec(CommandLineInputSpec): in_file = File(exists=True, argstr='%s', mandatory=True, position=-2, desc='input tractography') - out_file = File('tracked.vtk', argstr='%s', usedefault=True, position=-1, + out_file = File('tracks.vtk', argstr='%s', usedefault=True, position=-1, desc='output VTK file') reference = File( exists=True, argstr='-image %s', desc='if specified, the properties of' @@ -379,17 +379,18 @@ class TCK2VTKOutputSpec(TraitedSpec): class TCK2VTK(MRTrix3Base): """ - + Convert a track file to a vtk format, cave: coordinates are in XYZ + coordinates not reference Example ------- >>> import nipype.interfaces.mrtrix3 as mrt >>> vtk = mrt.TCK2VTK() - >>> vtk.inputs.in_file = 'tracked.tck' - >>> vtk.inputs.reference = 'dwi.nii.gz' + >>> vtk.inputs.in_file = 'tracks.tck' + >>> vtk.inputs.reference = 'b0.nii' >>> vtk.cmdline # doctest: +ELLIPSIS - 'tck2vtk -image dwi.nii.gz tracked.tck tracked.vtk' + 'tck2vtk -image b0.nii tracks.tck tracks.vtk' >>> vtk.run() # doctest: +SKIP """ From 432e0f6ffd9a402582f160d39a60f27d7fb8a49b Mon Sep 17 00:00:00 2001 From: oesteban Date: Thu, 16 Jul 2015 12:45:05 +0200 Subject: [PATCH 28/29] add FSL bvec/bval format explicit to all interfaces --- nipype/interfaces/mrtrix3/base.py | 24 +++++++++++++++++++ .../mrtrix3/tests/test_auto_BrainMask.py | 3 +++ .../mrtrix3/tests/test_auto_EstimateFOD.py | 3 +++ .../mrtrix3/tests/test_auto_FitTensor.py | 3 +++ .../mrtrix3/tests/test_auto_ResponseSD.py | 3 +++ .../mrtrix3/tests/test_auto_Tractography.py | 3 +++ 6 files changed, 39 insertions(+) diff --git a/nipype/interfaces/mrtrix3/base.py b/nipype/interfaces/mrtrix3/base.py index 1c6afdf13e..be5f3aaff4 100644 --- a/nipype/interfaces/mrtrix3/base.py +++ b/nipype/interfaces/mrtrix3/base.py @@ -44,6 +44,10 @@ class MRTrix3BaseInputSpec(CommandLineInputSpec): 'BValueScaling entry. Valid choices are yes / no, true / ' 'false, 0 / 1 (default: true).') + in_bvec = File(exists=True, argstr='-fslgrad %s %s', + desc='bvecs file in FSL format') + in_bval = File(exists=True, desc='bvals file in FSL format') + class MRTrix3Base(CommandLine): @@ -58,4 +62,24 @@ def _format_arg(self, name, trait_spec, value): pass return trait_spec.argstr % value + if name == 'in_bvec': + return trait_spec.argstr % (value, self.inputs.in_bval) + return super(MRTrix3Base, self)._format_arg(name, trait_spec, value) + + def _parse_inputs(self, skip=None): + if skip is None: + skip = [] + if (isdefined(self.inputs.grad_file) or + isdefined(self.inputs.grad_fsl)): + skip += ['in_bvec', 'in_bval'] + + is_bvec = isdefined(self.inputs.in_bvec) + is_bval = isdefined(self.inputs.in_bval) + if is_bvec or is_bval: + if not is_bvec or not is_bval: + raise RuntimeError('If using bvecs and bvals inputs, both' + 'should be defined') + skip += ['in_bval'] + + return super(MRTrix3Base, self)._parse_inputs(skip=skip) diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_BrainMask.py b/nipype/interfaces/mrtrix3/tests/test_auto_BrainMask.py index 0567f8b9ab..58b6184044 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_BrainMask.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_BrainMask.py @@ -17,6 +17,9 @@ def test_BrainMask_inputs(): ignore_exception=dict(nohash=True, usedefault=True, ), + in_bval=dict(), + in_bvec=dict(argstr='-fslgrad %s %s', + ), in_file=dict(argstr='%s', mandatory=True, position=-2, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py b/nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py index e01c948b8f..10ef4b33d0 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py @@ -17,6 +17,9 @@ def test_EstimateFOD_inputs(): ignore_exception=dict(nohash=True, usedefault=True, ), + in_bval=dict(), + in_bvec=dict(argstr='-fslgrad %s %s', + ), in_dirs=dict(argstr='-directions %s', ), in_file=dict(argstr='%s', diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_FitTensor.py b/nipype/interfaces/mrtrix3/tests/test_auto_FitTensor.py index 410e9a58b1..2dc23a5a3a 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_FitTensor.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_FitTensor.py @@ -17,6 +17,9 @@ def test_FitTensor_inputs(): ignore_exception=dict(nohash=True, usedefault=True, ), + in_bval=dict(), + in_bvec=dict(argstr='-fslgrad %s %s', + ), in_file=dict(argstr='%s', mandatory=True, position=-2, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_ResponseSD.py b/nipype/interfaces/mrtrix3/tests/test_auto_ResponseSD.py index 68cabe4fca..6bbc14c195 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_ResponseSD.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_ResponseSD.py @@ -19,6 +19,9 @@ def test_ResponseSD_inputs(): ignore_exception=dict(nohash=True, usedefault=True, ), + in_bval=dict(), + in_bvec=dict(argstr='-fslgrad %s %s', + ), in_file=dict(argstr='%s', mandatory=True, position=-2, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py b/nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py index 5b98797a4e..03154c5d8a 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py @@ -34,6 +34,9 @@ def test_Tractography_inputs(): ignore_exception=dict(nohash=True, usedefault=True, ), + in_bval=dict(), + in_bvec=dict(argstr='-fslgrad %s %s', + ), in_file=dict(argstr='%s', mandatory=True, position=-2, From 50f879358275d70bdefa6f8c5c9627a4c2a7f9b8 Mon Sep 17 00:00:00 2001 From: oesteban Date: Fri, 17 Jul 2015 10:59:56 +0200 Subject: [PATCH 29/29] fix parse_inputs for interfaces not defining gradients --- nipype/interfaces/mrtrix3/base.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/nipype/interfaces/mrtrix3/base.py b/nipype/interfaces/mrtrix3/base.py index be5f3aaff4..18432d760a 100644 --- a/nipype/interfaces/mrtrix3/base.py +++ b/nipype/interfaces/mrtrix3/base.py @@ -70,16 +70,20 @@ def _format_arg(self, name, trait_spec, value): def _parse_inputs(self, skip=None): if skip is None: skip = [] - if (isdefined(self.inputs.grad_file) or - isdefined(self.inputs.grad_fsl)): - skip += ['in_bvec', 'in_bval'] - - is_bvec = isdefined(self.inputs.in_bvec) - is_bval = isdefined(self.inputs.in_bval) - if is_bvec or is_bval: - if not is_bvec or not is_bval: - raise RuntimeError('If using bvecs and bvals inputs, both' - 'should be defined') - skip += ['in_bval'] + + try: + if (isdefined(self.inputs.grad_file) or + isdefined(self.inputs.grad_fsl)): + skip += ['in_bvec', 'in_bval'] + + is_bvec = isdefined(self.inputs.in_bvec) + is_bval = isdefined(self.inputs.in_bval) + if is_bvec or is_bval: + if not is_bvec or not is_bval: + raise RuntimeError('If using bvecs and bvals inputs, both' + 'should be defined') + skip += ['in_bval'] + except AttributeError: + pass return super(MRTrix3Base, self)._parse_inputs(skip=skip)