Repository: nipy/nipype

Issue:
MCFLIRT error
### Summary

I'm using MCFLIRT to correct motion of my data. Everything works, I get all the outputs expected, but in the end I get this error:
TraitError: The trait 'mean_img' of a MCFLIRTOutputSpec instance is an existing file name, but the path  '/Users/Abel-Gonzalez/msS06N-4D.nii.gz_mean_reg.nii.gz' does not exist.
Or sometimes: 
TraitError: The trait 'out_file' of a MCFLIRTOutputSpec instance ...

If I don't specify **out_file** in the code, it saves the outputs in my home directory.

### Script/Workflow details

`import nipype.interfaces.fsl as fsl`
`motionCorr = fsl.MCFLIRT(in_file="/Users/Abel-Gonzalez/Desktop/mcflirt/C06/sS06N-4D.nii.gz",
mean_vol=True, save_plots=True,
save_rms=True, save_mats=True,
out_file="/Users/Abel-Gonzalez/Desktop/mcflirt/C06/msS06N-4D.nii.gz")`
`motionCorr.run()`

### Error

---------------------------------------------------------------------------
TraitError                                Traceback (most recent call last)
<ipython-input-14-5da7fde1dffc> in <module>()
----> 1 mcflt1.run()

/anaconda3/lib/python3.6/site-packages/nipype/interfaces/base/core.py in run(self, cwd, ignore_exception, **inputs)
    521             runtime = self._run_interface(runtime)
    522             runtime = self._post_run_hook(runtime)
--> 523             outputs = self.aggregate_outputs(runtime)
    524         except Exception as e:
    525             import traceback

/anaconda3/lib/python3.6/site-packages/nipype/interfaces/base/core.py in aggregate_outputs(self, runtime, needed_outputs)
    618                                "'%s'." % (val, self.__class__.__name__, key))
    619                         raise FileNotFoundError(msg)
--> 620                     raise error
    621 
    622         return outputs

/anaconda3/lib/python3.6/site-packages/nipype/interfaces/base/core.py in aggregate_outputs(self, runtime, needed_outputs)
    611                                                       self.__class__.__name__))
    612                 try:
--> 613                     setattr(outputs, key, val)
    614                 except TraitError as error:
    615                     if getattr(error, 'info',

/anaconda3/lib/python3.6/site-packages/nipype/interfaces/base/traits_extension.py in validate(self, object, name, value)
    110                 args='The trait \'{}\' of {} instance is {}, but the path '
    111                 ' \'{}\' does not exist.'.format(name, class_of(object),
--> 112                                                  self.info_text, value))
    113 
    114         self.error(object, name, value)

TraitError: The trait 'mean_img' of a MCFLIRTOutputSpec instance is an existing file name, but the path  '/Users/Abel-Gonzalez/msS06N-4D.nii.gz_mean_reg.nii.gz' does not exist.


### Platform details:

macOS 10.13.6

<!-- Please run the following code from your shell and place the output between the triple ticks, below.
python -c "import nipype; from pprint import pprint; pprint(nipype.get_info())"
-->

```

```

### Execution environment

Choose one
- Container [Tag: ???]
- My python environment inside container [Base Tag: ???]
- My python environment outside container



Discussion:
If I run this directly through the command line `motionCorr.cmdline`:

`$ mcflirt -in /Users/Abel-Gonzalez/Desktop/mcflirt/C06/sS06N-4D.nii.gz -meanvol -out /Users/Abel-Gonzalez/Desktop/mcflirt/C06/msS06N-4D.nii.gz -mats -plots -rmsabs -rmsrel`

it works perfectly.
Yup, this looks like a problem with how MCFLIRT estimates the output file names. It assumes everything will be output into the current working directory, rather than the directory the output file is to be found in.
I'll try to submit a PR today or tomorrow.

Resolving patch:
diff --git a/nipype/interfaces/fsl/preprocess.py b/nipype/interfaces/fsl/preprocess.py
--- a/nipype/interfaces/fsl/preprocess.py
+++ b/nipype/interfaces/fsl/preprocess.py
@@ -820,16 +820,16 @@ def _format_arg(self, name, spec, value):
         return super(MCFLIRT, self)._format_arg(name, spec, value)
 
     def _list_outputs(self):
-        cwd = os.getcwd()
         outputs = self._outputs().get()
 
         outputs['out_file'] = self._gen_outfilename()
+        output_dir = os.path.dirname(outputs['out_file'])
 
         if isdefined(self.inputs.stats_imgs) and self.inputs.stats_imgs:
             outputs['variance_img'] = self._gen_fname(
-                outputs['out_file'] + '_variance.ext', cwd=cwd)
+                outputs['out_file'] + '_variance.ext', cwd=output_dir)
             outputs['std_img'] = self._gen_fname(
-                outputs['out_file'] + '_sigma.ext', cwd=cwd)
+                outputs['out_file'] + '_sigma.ext', cwd=output_dir)
 
         # The mean image created if -stats option is specified ('meanvol')
         # is missing the top and bottom slices. Therefore we only expose the
@@ -839,11 +839,11 @@ def _list_outputs(self):
 
         if isdefined(self.inputs.mean_vol) and self.inputs.mean_vol:
             outputs['mean_img'] = self._gen_fname(
-                outputs['out_file'] + '_mean_reg.ext', cwd=cwd)
+                outputs['out_file'] + '_mean_reg.ext', cwd=output_dir)
 
         if isdefined(self.inputs.save_mats) and self.inputs.save_mats:
             _, filename = os.path.split(outputs['out_file'])
-            matpathname = os.path.join(cwd, filename + '.mat')
+            matpathname = os.path.join(output_dir, filename + '.mat')
             _, _, _, timepoints = load(self.inputs.in_file).shape
             outputs['mat_file'] = []
             for t in range(timepoints):


Test patch: