nipype
nipype copied to clipboard
MCFLIRT naming error with FSL 6.0.7.13
Summary
I'm walking through miykael's tutorial and found the output of mcflirt could not be correctly recognized:
FileNotFoundError: No such file or directory '/xxx/working_dir/preprocWF/mcflirt/sub-01_ses-test_task-fingerfootlips_bold_mcf_mean_reg.nii.gz' for output 'mean_img' of a MCFLIRT interface
and the real output name of mcflirt was sub-01_ses-test_task-fingerfootlips_bold_mcf.nii.gz_mean_reg.nii.gz.
I think this issue should have been resolved after referring to a previous commit.
By simply replacing this line with the hardcoded path of the output file, the workflow finished without any error.
I don't know if this pattern of filename (.nii.gz_mean_reg.nii.gz) shouldn't appear in FLS 6, or there's something wrong on nipype side?
Platform details:
{'commit_hash': '62fc392',
'commit_source': 'repository',
'networkx_version': '3.3',
'nibabel_version': '5.2.1',
'nipype_version': '1.8.6',
'numpy_version': '1.26.3',
'pkg_path': '/xxx/.pyenv/versions/3.11.10/lib/python3.11/site-packages/nipype',
'scipy_version': '1.14.1',
'sys_executable': '/xxx/.pyenv/versions/3.11.10/bin/python',
'sys_platform': 'linux',
'sys_version': '3.11.10 (main, Sep 23 2024, 14:48:25) [GCC 7.5.0]',
'traits_version': '6.3.2'}
Execution environment
FSL: 6.0.7.13
I'm not sure. If you're able to describe an environment and minimal reproducible example, we could definitely debug this.
I'm just refering to the nipype tutorial:
from nipype import SelectFiles, Node
from os.path import abspath
templates={'func': '{subject}/{session}/func/{subject}_{session}_task-fingerfootlips_bold.nii.gz'}
sf = Node(SelectFiles(templates),
name='selectfiles')
sf.inputs.base_directory = abspath('../data/ds000114')
sf.inputs.subject = 'sub-01'
sf.inputs.session = 'ses-test'
from nipype.interfaces.fsl import MCFLIRT, IsotropicSmooth
mcflirt = Node(MCFLIRT(mean_vol=True,
save_plots=True),
name='mcflirt')
smooth = Node(IsotropicSmooth(fwhm=4),
name='smooth')
from nipype import Workflow
wf = Workflow(name="preprocWF")
wf.base_dir = 'output/working_dir'
wf.connect([(sf, mcflirt, [("func", "in_file")]),
#(mcflirt, smooth, [("out_file", "in_file")])
])
wf.run()
Hi, I noticed an issue when running mcflirt from the command line using:
mcflirt -in name.nii -meanvol -out outname.nii
This produces an output file named outname.nii.nii, which causes a naming error. The same behavior occurs when using Nipype unless you explicitly specify the output filename without the .nii extension. In my Python code, I work around this by setting out_file='outname':
mcflirt = Node(MCFLIRT(mean_vol=True,
save_plots=True),
name='mcflirt', out_file='outname')
Then modify nipype MCFLIRT class
class MCFLIRT(FSLCommand):
def _list_outputs(self):
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:
if LooseVersion(Info.version()) < LooseVersion("6.0.0"):
# FSL <6.0 outputs have .nii.gz_variance.nii.gz as extension
outputs["variance_img"] = self._gen_fname(
outputs["out_file"] + "_variance.ext", cwd=output_dir
)
outputs["std_img"] = self._gen_fname(
outputs["out_file"] + "_sigma.ext", cwd=output_dir
)
else:
outputs["variance_img"] = self._gen_fname(
outputs["out_file"], suffix="_variance", cwd=output_dir
)
outputs["std_img"] = self._gen_fname(
outputs["out_file"], suffix="_sigma", 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
# mean image created by -meanvol option ('mean_reg') which isn't
# corrupted.
# Note that the same problem holds for the std and variance image.
if isdefined(self.inputs.mean_vol) and self.inputs.mean_vol:
if LooseVersion(Info.version()) < LooseVersion("6.0.0"):
# FSL <6.0 outputs have .nii.gz_mean_img.nii.gz as extension
outputs["mean_img"] = self._gen_fname(
outputs["out_file"] + "_mean_reg.ext", cwd=output_dir
)
else:
outputs["mean_img"] = self._gen_fname(
outputs["out_file"], suffix="_mean_reg", 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(output_dir, filename + ".mat")
_, _, _, timepoints = load(self.inputs.in_file).shape
outputs["mat_file"] = []
for t in range(timepoints):
outputs["mat_file"].append(os.path.join(matpathname, "MAT_%04d" % t))
if isdefined(self.inputs.save_plots) and self.inputs.save_plots:
# Note - if e.g. out_file has .nii.gz, you get .nii.gz.par,
# which is what mcflirt does!
outputs["par_file"] = outputs["out_file"] + ".par"
if isdefined(self.inputs.save_rms) and self.inputs.save_rms:
outfile = outputs["out_file"]
outputs["rms_files"] = [outfile + "_abs.rms", outfile + "_rel.rms"]
#! add this line ************************************
outputs["out_file"] = outputs["out_file"] + ".nii" # .nii or .nii.gz depend on your output
#! end of add
return outputs
Hope this help