diff --git a/.zenodo.json b/.zenodo.json index 0baed9eaa9..eb0bafe320 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -788,6 +788,11 @@ { "name": "Tambini, Arielle" }, + { + "affiliation": "Weill Cornell Medicine", + "name": "Xie, Xihe", + "orcid": "0000-0001-6595-2473" + }, { "affiliation": "Max Planck Institute for Human Cognitive and Brain Sciences, Leipzig, Germany.", "name": "Mihai, Paul Glad", diff --git a/nipype/interfaces/mrtrix3/__init__.py b/nipype/interfaces/mrtrix3/__init__.py index f60e837310..53af56ef65 100644 --- a/nipype/interfaces/mrtrix3/__init__.py +++ b/nipype/interfaces/mrtrix3/__init__.py @@ -18,6 +18,7 @@ ResponseSD, ACTPrepareFSL, ReplaceFSwithFIRST, + DWIPreproc, DWIDenoise, MRDeGibbs, DWIBiasCorrect, diff --git a/nipype/interfaces/mrtrix3/preprocess.py b/nipype/interfaces/mrtrix3/preprocess.py index aa3347c7f9..ef67365f0b 100644 --- a/nipype/interfaces/mrtrix3/preprocess.py +++ b/nipype/interfaces/mrtrix3/preprocess.py @@ -233,6 +233,7 @@ class DWIBiasCorrect(MRTrix3Base): _cmd = "dwibiascorrect" input_spec = DWIBiasCorrectInputSpec output_spec = DWIBiasCorrectOutputSpec + def _format_arg(self, name, trait_spec, value): if name in ("use_ants", "use_fsl"): ver = self.version @@ -241,6 +242,139 @@ def _format_arg(self, name, trait_spec, value): return f"-{trait_spec.argstr}" return super()._format_arg(name, trait_spec, value) + +class DWIPreprocInputSpec(MRTrix3BaseInputSpec): + in_file = File( + exists=True, argstr="%s", position=0, mandatory=True, desc="input DWI image" + ) + out_file = File( + "preproc.mif", + argstr="%s", + mandatory=True, + position=1, + usedefault=True, + desc="output file after preprocessing", + ) + rpe_options = traits.Enum( + "none", + "pair", + "all", + "header", + argstr="-rpe_%s", + position=2, + mandatory=True, + desc='Specify acquisition phase-encoding design. "none" for no reversed phase-encoding image, "all" for all DWIs have opposing phase-encoding acquisition, "pair" for using a pair of b0 volumes for inhomogeneity field estimation only, and "header" for phase-encoding information can be found in the image header(s)', + ) + pe_dir = traits.Str( + argstr="-pe_dir %s", + mandatory=True, + desc="Specify the phase encoding direction of the input series, can be a signed axis number (e.g. -0, 1, +2), an axis designator (e.g. RL, PA, IS), or NIfTI axis codes (e.g. i-, j, k)", + ) + ro_time = traits.Float( + argstr="-readout_time %f", + desc="Total readout time of input series (in seconds)", + ) + in_epi = File( + exists=True, + argstr="-se_epi %s", + desc="Provide an additional image series consisting of spin-echo EPI images, which is to be used exclusively by topup for estimating the inhomogeneity field (i.e. it will not form part of the output image series)", + ) + align_seepi = traits.Bool( + argstr="-align_seepi", + desc="Achieve alignment between the SE-EPI images used for inhomogeneity field estimation, and the DWIs", + ) + eddy_options = traits.Str( + argstr='-eddy_options "%s"', + desc="Manually provide additional command-line options to the eddy command", + ) + topup_options = traits.Str( + argstr='-topup_options "%s"', + desc="Manually provide additional command-line options to the topup command", + ) + export_grad_mrtrix = traits.Bool( + argstr="-export_grad_mrtrix", desc="export new gradient files in mrtrix format" + ) + export_grad_fsl = traits.Bool( + argstr="-export_grad_fsl", desc="export gradient files in FSL format" + ) + out_grad_mrtrix = File( + "grad.b", + argstr="%s", + usedefault=True, + requires=["export_grad_mrtrix"], + desc="name of new gradient file", + ) + out_grad_fsl = traits.Tuple( + File("grad.bvecs", usedefault=True, desc="bvecs"), + File("grad.bvals", usedefault=True, desc="bvals"), + argstr="%s, %s", + requires=["export_grad_fsl"], + desc="Output (bvecs, bvals) gradients FSL format", + ) + + +class DWIPreprocOutputSpec(TraitedSpec): + out_file = File(argstr="%s", desc="output preprocessed image series") + out_grad_mrtrix = File( + "grad.b", + argstr="%s", + usedefault=True, + desc="preprocessed gradient file in mrtrix3 format", + ) + out_fsl_bvec = File( + "grad.bvecs", + argstr="%s", + usedefault=True, + desc="exported fsl gradient bvec file", + ) + out_fsl_bval = File( + "grad.bvals", + argstr="%s", + usedefault=True, + desc="exported fsl gradient bval file", + ) + + +class DWIPreproc(MRTrix3Base): + """ + Perform diffusion image pre-processing using FSL's eddy tool; including inhomogeneity distortion correction using FSL's topup tool if possible + + For more information, see + + + Example + ------- + + >>> import nipype.interfaces.mrtrix3 as mrt + >>> preproc = mrt.DWIPreproc() + >>> preproc.inputs.in_file = 'dwi.mif' + >>> preproc.inputs.rpe_options = 'none' + >>> preproc.inputs.out_file = "preproc.mif" + >>> preproc.inputs.eddy_options = '--slm=linear --repol' # linear second level model and replace outliers + >>> preproc.inputs.export_grad_mrtrix = True # export final gradient table in MRtrix format + >>> preproc.inputs.ro_time = 0.165240 # 'TotalReadoutTime' in BIDS JSON metadata files + >>> preproc.inputs.pe_dir = 'j' # 'PhaseEncodingDirection' in BIDS JSON metadata files + >>> preproc.cmdline + 'dwifslpreproc dwi.mif preproc.mif -rpe_none -eddy_options "--slm=linear --repol" -export_grad_mrtrix grad.b -pe_dir j -readout_time 0.165240' + >>> preproc.run() # doctest: +SKIP + """ + + _cmd = "dwifslpreproc" + input_spec = DWIPreprocInputSpec + output_spec = DWIPreprocOutputSpec + + def _list_outputs(self): + outputs = self.output_spec().get() + outputs["out_file"] = op.abspath(self.inputs.out_file) + if self.inputs.export_grad_mrtrix: + outputs["out_grad_mrtrix"] = op.abspath(self.inputs.out_grad_mrtrix) + if self.inputs.export_grad_fsl: + outputs["out_fsl_bvec"] = op.abspath(self.inputs.out_grad_fsl[0]) + outputs["out_fsl_bval"] = op.abspath(self.inputs.out_grad_fsl[1]) + + return outputs + + class ResponseSDInputSpec(MRTrix3BaseInputSpec): algorithm = traits.Enum( "msmt_5tt", diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_DWIPreproc.py b/nipype/interfaces/mrtrix3/tests/test_auto_DWIPreproc.py new file mode 100644 index 0000000000..76fae6548f --- /dev/null +++ b/nipype/interfaces/mrtrix3/tests/test_auto_DWIPreproc.py @@ -0,0 +1,54 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from ..preprocess import DWIPreproc + + +def test_DWIPreproc_inputs(): + input_map = dict( + align_seepi=dict(argstr="-align_seepi"), + args=dict(argstr="%s"), + bval_scale=dict(argstr="-bvalue_scaling %s"), + eddy_options=dict(argstr='-eddy_options "%s"'), + environ=dict(nohash=True, usedefault=True), + export_grad_fsl=dict(argstr="-export_grad_fsl"), + export_grad_mrtrix=dict(argstr="-export_grad_mrtrix"), + grad_file=dict(argstr="-grad %s", extensions=None, xor=["grad_fsl"]), + grad_fsl=dict(argstr="-fslgrad %s %s", xor=["grad_file"]), + in_bval=dict(extensions=None), + in_bvec=dict(argstr="-fslgrad %s %s", extensions=None), + in_epi=dict(argstr="-se_epi %s", extensions=None), + in_file=dict(argstr="%s", extensions=None, mandatory=True, position=0), + nthreads=dict(argstr="-nthreads %d", nohash=True), + out_file=dict( + argstr="%s", extensions=None, mandatory=True, position=1, usedefault=True + ), + out_grad_fsl=dict(argstr="%s, %s", requires=["export_grad_fsl"]), + out_grad_mrtrix=dict( + argstr="%s", + extensions=None, + requires=["export_grad_mrtrix"], + usedefault=True, + ), + pe_dir=dict(argstr="-pe_dir %s", mandatory=True), + ro_time=dict(argstr="-readout_time %f"), + rpe_options=dict(argstr="-rpe_%s", mandatory=True, position=2), + topup_options=dict(argstr='-topup_options "%s"'), + ) + inputs = DWIPreproc.input_spec() + + for key, metadata in list(input_map.items()): + for metakey, value in list(metadata.items()): + assert getattr(inputs.traits()[key], metakey) == value + + +def test_DWIPreproc_outputs(): + output_map = dict( + out_file=dict(argstr="%s", extensions=None), + out_fsl_bval=dict(argstr="%s", extensions=None, usedefault=True), + out_fsl_bvec=dict(argstr="%s", extensions=None, usedefault=True), + out_grad_mrtrix=dict(argstr="%s", extensions=None, usedefault=True), + ) + outputs = DWIPreproc.output_spec() + + for key, metadata in list(output_map.items()): + for metakey, value in list(metadata.items()): + assert getattr(outputs.traits()[key], metakey) == value diff --git a/nipype/testing/data/grad.b b/nipype/testing/data/grad.b new file mode 100644 index 0000000000..e69de29bb2