Repository: nipy/nipype

Issue:
Mrtrix3's DWIPreproc force inputs that are not mandatory
### Summary
The interface to Mrtrix3's dwifslpreproc forces some inputs that are not really necessary according to [the original CLI on which it relies](https://mrtrix.readthedocs.io/en/dev/reference/commands/dwifslpreproc.html).

### Actual behavior
The interface requires inputs to be set for out_grad_mrtrix, pe_dir, etc.

### Expected behavior
Ideally, it would change the necessary inputs (that are different and depends on the way you use this CLI).
A simpler solution would be to simply reduce the mandatory inputs to those that truly are.

python -c "import nipype; from pprint import pprint; pprint(nipype.get_info())"
-->

```
{'commit_hash': 'd77fc3c',
 'commit_source': 'installation',
 'networkx_version': '2.6.3',
 'nibabel_version': '3.2.1',
 'nipype_version': '1.8.0',
 'numpy_version': '1.20.0',
 'pkg_path': '/home/groot/Projects/PhD/venv/lib/python3.9/site-packages/nipype',
 'scipy_version': '1.7.3',
 'sys_executable': '/home/groot/Projects/PhD/venv/bin/python',
 'sys_platform': 'linux',
 'sys_version': '3.9.12 (main, Mar 24 2022, 16:20:11) \n[GCC 9.4.0]',
 'traits_version': '6.3.2'}
```

### Execution environment
- My python environment outside container



Discussion:

Resolving patch:
diff --git a/nipype/interfaces/mrtrix3/preprocess.py b/nipype/interfaces/mrtrix3/preprocess.py
--- a/nipype/interfaces/mrtrix3/preprocess.py
+++ b/nipype/interfaces/mrtrix3/preprocess.py
@@ -5,21 +5,26 @@
 import os.path as op
 
 from ..base import (
-    CommandLineInputSpec,
     CommandLine,
-    traits,
-    TraitedSpec,
+    CommandLineInputSpec,
+    Directory,
     File,
-    isdefined,
-    Undefined,
     InputMultiObject,
+    TraitedSpec,
+    Undefined,
+    isdefined,
+    traits,
 )
-from .base import MRTrix3BaseInputSpec, MRTrix3Base
+from .base import MRTrix3Base, MRTrix3BaseInputSpec
 
 
 class DWIDenoiseInputSpec(MRTrix3BaseInputSpec):
     in_file = File(
-        exists=True, argstr="%s", position=-2, mandatory=True, desc="input DWI image"
+        exists=True,
+        argstr="%s",
+        position=-2,
+        mandatory=True,
+        desc="input DWI image",
     )
     mask = File(exists=True, argstr="-mask %s", position=1, desc="mask image")
     extent = traits.Tuple(
@@ -88,7 +93,11 @@ class DWIDenoise(MRTrix3Base):
 
 class MRDeGibbsInputSpec(MRTrix3BaseInputSpec):
     in_file = File(
-        exists=True, argstr="%s", position=-2, mandatory=True, desc="input DWI image"
+        exists=True,
+        argstr="%s",
+        position=-2,
+        mandatory=True,
+        desc="input DWI image",
     )
     axes = traits.ListInt(
         default_value=[0, 1],
@@ -177,7 +186,11 @@ class MRDeGibbs(MRTrix3Base):
 
 class DWIBiasCorrectInputSpec(MRTrix3BaseInputSpec):
     in_file = File(
-        exists=True, argstr="%s", position=-2, mandatory=True, desc="input DWI image"
+        exists=True,
+        argstr="%s",
+        position=-2,
+        mandatory=True,
+        desc="input DWI image",
     )
     in_mask = File(argstr="-mask %s", desc="input mask image for bias field estimation")
     use_ants = traits.Bool(
@@ -252,7 +265,11 @@ def _list_outputs(self):
 
 class DWIPreprocInputSpec(MRTrix3BaseInputSpec):
     in_file = File(
-        exists=True, argstr="%s", position=0, mandatory=True, desc="input DWI image"
+        exists=True,
+        argstr="%s",
+        position=0,
+        mandatory=True,
+        desc="input DWI image",
     )
     out_file = File(
         "preproc.mif",
@@ -274,7 +291,6 @@ class DWIPreprocInputSpec(MRTrix3BaseInputSpec):
     )
     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(
@@ -290,33 +306,49 @@ class DWIPreprocInputSpec(MRTrix3BaseInputSpec):
         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",
+    json_import = File(
+        exists=True,
+        argstr="-json_import %s",
+        desc="Import image header information from an associated JSON file (may be necessary to determine phase encoding information)",
     )
     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"
+    eddy_options = traits.Str(
+        argstr='-eddy_options "%s"',
+        desc="Manually provide additional command-line options to the eddy command",
+    )
+    eddy_mask = File(
+        exists=True,
+        argstr="-eddy_mask %s",
+        desc="Provide a processing mask to use for eddy, instead of having dwifslpreproc generate one internally using dwi2mask",
+    )
+    eddy_slspec = File(
+        exists=True,
+        argstr="-eddy_slspec %s",
+        desc="Provide a file containing slice groupings for eddy's slice-to-volume registration",
+    )
+    eddyqc_text = Directory(
+        exists=False,
+        argstr="-eddyqc_text %s",
+        desc="Copy the various text-based statistical outputs generated by eddy, and the output of eddy_qc (if installed), into an output directory",
     )
-    export_grad_fsl = traits.Bool(
-        argstr="-export_grad_fsl", desc="export gradient files in FSL format"
+    eddyqc_all = Directory(
+        exists=False,
+        argstr="-eddyqc_all %s",
+        desc="Copy ALL outputs generated by eddy (including images), and the output of eddy_qc (if installed), into an output directory",
     )
     out_grad_mrtrix = File(
         "grad.b",
-        argstr="%s",
-        usedefault=True,
-        requires=["export_grad_mrtrix"],
-        desc="name of new gradient file",
+        argstr="-export_grad_mrtrix %s",
+        desc="export new gradient files in mrtrix format",
     )
     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",
+        File("grad.bvecs", desc="bvecs"),
+        File("grad.bvals", desc="bvals"),
+        argstr="-export_grad_fsl %s, %s",
+        desc="export gradient files in FSL format",
     )
 
 
@@ -358,7 +390,7 @@ class DWIPreproc(MRTrix3Base):
     >>> 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.out_grad_mrtrix = "grad.b"    # 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
@@ -394,7 +426,11 @@ class ResponseSDInputSpec(MRTrix3BaseInputSpec):
         desc="response estimation algorithm (multi-tissue)",
     )
     in_file = File(
-        exists=True, argstr="%s", position=-5, mandatory=True, desc="input DWI image"
+        exists=True,
+        argstr="%s",
+        position=-5,
+        mandatory=True,
+        desc="input DWI image",
     )
     mtt_file = File(argstr="%s", position=-4, desc="input 5tt image")
     wm_file = File(
@@ -518,10 +554,17 @@ class ReplaceFSwithFIRSTInputSpec(CommandLineInputSpec):
         desc="input anatomical image",
     )
     in_t1w = File(
-        exists=True, argstr="%s", mandatory=True, position=-3, desc="input T1 image"
+        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"
+        exists=True,
+        argstr="%s",
+        position=-2,
+        desc="connectome configuration file",
     )
 
     out_file = File(


Test patch:
diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_DWIPreproc.py b/nipype/interfaces/mrtrix3/tests/test_auto_DWIPreproc.py
--- a/nipype/interfaces/mrtrix3/tests/test_auto_DWIPreproc.py
+++ b/nipype/interfaces/mrtrix3/tests/test_auto_DWIPreproc.py
@@ -13,19 +13,27 @@ def test_DWIPreproc_inputs():
         bval_scale=dict(
             argstr="-bvalue_scaling %s",
         ),
+        eddy_mask=dict(
+            argstr="-eddy_mask %s",
+            extensions=None,
+        ),
         eddy_options=dict(
             argstr='-eddy_options "%s"',
         ),
+        eddy_slspec=dict(
+            argstr="-eddy_slspec %s",
+            extensions=None,
+        ),
+        eddyqc_all=dict(
+            argstr="-eddyqc_all %s",
+        ),
+        eddyqc_text=dict(
+            argstr="-eddyqc_text %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,
@@ -52,6 +60,10 @@ def test_DWIPreproc_inputs():
             mandatory=True,
             position=0,
         ),
+        json_import=dict(
+            argstr="-json_import %s",
+            extensions=None,
+        ),
         nthreads=dict(
             argstr="-nthreads %d",
             nohash=True,
@@ -71,18 +83,14 @@ def test_DWIPreproc_inputs():
             usedefault=True,
         ),
         out_grad_fsl=dict(
-            argstr="%s, %s",
-            requires=["export_grad_fsl"],
+            argstr="-export_grad_fsl %s, %s",
         ),
         out_grad_mrtrix=dict(
-            argstr="%s",
+            argstr="-export_grad_mrtrix %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",