Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nipype.interfaces.cat12.preprocess.CAT12Segment FileNotFoundError: No such file or directory '/[....]/catROIs_T1w.xml' for output 'label_rois' of a CAT12Segment interface #3654

Open
JohannesWiesner opened this issue Jun 6, 2024 · 5 comments

Comments

@JohannesWiesner
Copy link

Summary

I am running the Cat12Segment on a single T1w image. I don't want to run the surface reconstruction workflow so I set surface_and_thickness_estimation=0, and surface_measures=0.

Actual behavior

This is the error I get:

NodeExecutionError: Exception raised while executing Node cat12segment.

Traceback:
	Traceback (most recent call last):
	  File "/csp-tools/anaconda3/envs/csp_wiesner_johannes/lib/python3.9/site-packages/nipype/interfaces/base/core.py", line 453, in aggregate_outputs
	    setattr(outputs, key, val)
	  File "/csp-tools/anaconda3/envs/csp_wiesner_johannes/lib/python3.9/site-packages/nipype/interfaces/base/traits_extension.py", line 330, in validate
	    value = super(File, self).validate(objekt, name, value, return_pathlike=True)
	  File "/csp-tools/anaconda3/envs/csp_wiesner_johannes/lib/python3.9/site-packages/nipype/interfaces/base/traits_extension.py", line 135, in validate
	    self.error(objekt, name, str(value))
	  File "/csp-tools/anaconda3/envs/csp_wiesner_johannes/lib/python3.9/site-packages/traits/base_trait_handler.py", line 74, in error
	    raise TraitError(
	traits.trait_errors.TraitError: The 'label_rois' trait of a CAT12SegmentOutputSpec instance must be a pathlike object or string representing an existing file, but a value of '/pandora/home/johannes.wiesner/work/testing/debug_cat12/cat12segment/label/catROIs_T1w.xml' <class 'str'> was specified.

	During handling of the above exception, another exception occurred:

	Traceback (most recent call last):
	  File "/csp-tools/anaconda3/envs/csp_wiesner_johannes/lib/python3.9/site-packages/nipype/interfaces/base/core.py", line 400, in run
	    outputs = self.aggregate_outputs(runtime)
	  File "/csp-tools/anaconda3/envs/csp_wiesner_johannes/lib/python3.9/site-packages/nipype/interfaces/base/core.py", line 460, in aggregate_outputs
	    raise FileNotFoundError(msg)
	FileNotFoundError: No such file or directory '/pandora/home/johannes.wiesner/work/testing/debug_cat12/cat12segment/label/catROIs_T1w.xml' for output 'label_rois' of a CAT12Segment interface

Expected behavior

Only run the VBM-process of CAT12 (aka. only output mwp1, mwp2, etc.) but don't run the surface reconstruction.

I currently have two hypotheses (please take these with a big grain of salt, I am new to CAT12) what is causing the error:

1.) If I inspect the nodes output I can see that there is /pandora/home/johannes.wiesner/work/testing/debug_cat12/cat12segment/label/catROIs_T1w.xml but not /pandora/home/johannes.wiesner/work/testing/debug_cat12/cat12segment/label/catROI_T1w.xml (s at the end!)

So the filename might have changed in later versions of CAT12? Probably @ChristianGaser can answer this?

2.) If I inspect the generated pyscript.m file I can see that even though jobs{1}.spm.tools.cat.estwrite.output.surf_measures = 0; is appropriatly set to 0 these other lines are still added:

jobs{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.neuromorphometrics = 1;
jobs{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.lpba40 = 1;
jobs{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.hammers = 1;
jobs{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.cobra = 1;

which to me looks like as if we want to extract ROI labels for these atlases even though we didn't want them in the first place? In the GUI version the equivalent would be "if user doesn't want ROI estimates, then don't open dropdown menu where user can choose atlases" (I can confirm that this happens here). So either these lines should not even exist in the first place or the values should be set to 0 if surf_measures = 0?

Here's the full pyscript_cat12segment.m file:

fprintf(1,'Executing %s at %s:\n',mfilename(),datestr(now));
fprintf(1,'Executing %s at %s:\n',mfilename(),datestr(now));
ver,
try,
        %% Generated by nipype.interfaces.spm
        if isempty(which('spm')),
             throw(MException('SPMCheck:NotFound', 'SPM not in matlab path'));
        end
        [name, version] = spm('ver');
        fprintf('SPM version: %s Release: %s\n',name, version);
        fprintf('SPM path: %s\n', which('spm'));
        spm('Defaults','fMRI');

        if strcmp(name, 'SPM8') || strcmp(name(1:5), 'SPM12'),
           spm_jobman('initcfg');
           spm_get_defaults('cmdline', 1);
        end

        jobs{1}.spm.tools.cat.estwrite.data = {...
'/pandora/home/johannes.wiesner/work/testing/debug_cat12/cat12segment/T1w.nii,1';...
};
jobs{1}.spm.tools.cat.estwrite.nproc = 1;
jobs{1}.spm.tools.cat.estwrite.opts.affreg = 'mni';
jobs{1}.spm.tools.cat.estwrite.opts.biasacc = 0.5;
jobs{1}.spm.tools.cat.estwrite.extopts.APP = 1070;
jobs{1}.spm.tools.cat.estwrite.extopts.spm_kamap = 0;
jobs{1}.spm.tools.cat.estwrite.extopts.LASstr = 0.5;
jobs{1}.spm.tools.cat.estwrite.extopts.gcutstr = 2;
jobs{1}.spm.tools.cat.estwrite.extopts.WMHC = 1;
jobs{1}.spm.tools.cat.estwrite.extopts.vox = 1.5;
jobs{1}.spm.tools.cat.estwrite.extopts.restypes.optimal(1) = 1;
jobs{1}.spm.tools.cat.estwrite.extopts.restypes.optimal(2) = 0.1;
jobs{1}.spm.tools.cat.estwrite.extopts.ignoreErrors = 1;
jobs{1}.spm.tools.cat.estwrite.surface = 0;
jobs{1}.spm.tools.cat.estwrite.output.surf_measures = 0;
jobs{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.neuromorphometrics = 1;
jobs{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.lpba40 = 1;
jobs{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.hammers = 1;
jobs{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.cobra = 1;
jobs{1}.spm.tools.cat.estwrite.output.GM.native = 0;
jobs{1}.spm.tools.cat.estwrite.output.GM.mod = 1;
jobs{1}.spm.tools.cat.estwrite.output.GM.dartel = 0;
jobs{1}.spm.tools.cat.estwrite.output.WM.native = 0;
jobs{1}.spm.tools.cat.estwrite.output.WM.mod = 1;
jobs{1}.spm.tools.cat.estwrite.output.WM.dartel = 0;
jobs{1}.spm.tools.cat.estwrite.output.CSF.native = 0;
jobs{1}.spm.tools.cat.estwrite.output.CSF.mod = 1;
jobs{1}.spm.tools.cat.estwrite.output.CSF.dartel = 0;
jobs{1}.spm.tools.cat.estwrite.output.label.native = 0;
jobs{1}.spm.tools.cat.estwrite.output.label.warped = 1;
jobs{1}.spm.tools.cat.estwrite.output.label.dartel = 0;
jobs{1}.spm.tools.cat.estwrite.output.labelnative = 0;
jobs{1}.spm.tools.cat.estwrite.output.bias.warped = 1;
jobs{1}.spm.tools.cat.estwrite.output.las.native = 0;
jobs{1}.spm.tools.cat.estwrite.output.las.warped = 1;
jobs{1}.spm.tools.cat.estwrite.output.las.dartel = 0;
jobs{1}.spm.tools.cat.estwrite.output.jacobianwarped = 1;
jobs{1}.spm.tools.cat.estwrite.output.warps(1) = 1;
jobs{1}.spm.tools.cat.estwrite.output.warps(2) = 0;

        spm_jobman('run', jobs);

        
,catch ME,
fprintf(2,'MATLAB code threw an exception:\n');
fprintf(2,'%s\n',ME.message);
if length(ME.stack) ~= 0, fprintf(2,'File:%s\nName:%s\nLine:%d\n',ME.stack.file,ME.stack.name,ME.stack.line);, end;
end;

How to replicate the behavior

Here's a python script to reproduce the error

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Debug CAT12Segment
"""

import subprocess
from nipype.interfaces.cat12.preprocess import CAT12Segment
from nipype import Node
import os 

###############################################################################
# Preparation: Download an anatomical files from a public available AWS-bucket 
###############################################################################

# download T1w image
command = """
curl \
--create-dirs https://s3.amazonaws.com/openneuro.org/ds004302/sub-02/anat/sub-02_T1w.nii.gz?versionId=93eQ.AwPcMeccJAT3sO9otYv4A_WH3Bj  \
-o ./T1w.nii.gz
"""
subprocess.run(command,shell=True)

# gunzip image to get from .nii.gz to .nii
subprocess.run("gunzip -c ./T1w.nii.gz > T1w.nii",shell=True)

# get the full path to the directory where this script is being executed
script_dir = os.path.dirname(os.path.realpath(__file__))

# get full path to both images (nipype always needs absolut paths to inputs)
image_nii = os.path.join(script_dir,'T1w.nii')
image_nii_gz = os.path.join(script_dir,'T1w.nii.gz')

###############################################################################
# Run CAT12Segment inside a node on one image
###############################################################################

# create node
cat12segment = Node(CAT12Segment(surface_and_thickness_estimation=0,
                                 surface_measures=0),
                    name='cat12segment')

# input image (uncompressed, see nipype issue #3653). But should actually
# also work for .nii.gz files
cat12segment.inputs.in_files = image_nii

# set working directory of node to script directory
cat12segment.base_dir = script_dir

# run the node
cat12segment.run()

Platform details:

{'commit_hash': '%h',
 'commit_source': 'archive substitution',
 'networkx_version': '3.2.1',
 'nibabel_version': '5.2.0',
 'nipype_version': '1.8.6',
 'numpy_version': '1.26.3',
 'pkg_path': '/csp-tools/anaconda3/envs/csp_wiesner_johannes/lib/python3.9/site-packages/nipype',
 'scipy_version': '1.12.0',
 'sys_executable': '/csp-tools/anaconda3/envs/csp_wiesner_johannes/bin/python',
 'sys_platform': 'linux',
 'sys_version': '3.9.18 | packaged by conda-forge | (main, Dec 23 2023, '
                '16:33:10) \n'
                '[GCC 12.3.0]',
 'traits_version': '6.3.2'}


Execution environment

Choose one

  • My python environment outside container. My CAT12 version is CAT12.9 (r2560) inside an spm12/9.14 environment module that is loaded using module load spm12/9.14 in my .bashrc file.
@ChristianGaser
Copy link

ChristianGaser commented Jun 7, 2024 via email

@ChristianGaser
Copy link

ChristianGaser commented Jun 7, 2024 via email

@JohannesWiesner
Copy link
Author

Hi @ChristianGaser, I guess that goes in the direction of my hypotheses. Can you confirm the following, then we might be able to send a PR:

The following lines of code

jobs{1}.spm.tools.cat.estwrite.output.surf_measures = 0;
jobs{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.neuromorphometrics = 1;
jobs{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.lpba40 = 1;
jobs{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.hammers = 1;
jobs{1}.spm.tools.cat.estwrite.output.ROImenu.atlases.cobra = 1;

should be replaced with

jobs{1}.spm.tools.cat.estwrite.output.surf_measures = 0;
jobs{1}.spm.tools.cat.estwrite.output.ROImenu.noROI = struct([]);

?

@ChristianGaser
Copy link

ChristianGaser commented Jun 7, 2024 via email

JailanOweda pushed a commit to JailanOweda/nipype that referenced this issue Jun 12, 2024
JailanOweda added a commit to JailanOweda/nipype that referenced this issue Jun 13, 2024
FIX Issue nipy#3654: added no surface measure (no ROI) option to cat12…
JailanOweda pushed a commit to JailanOweda/nipype that referenced this issue Jun 14, 2024
…ted if statements for when no surface or ROI estimations are desired
JailanOweda added a commit to JailanOweda/nipype that referenced this issue Jun 14, 2024
FIX Issue nipy#3654: added missing input traits for templates, corrected …
@JailanOweda
Copy link

@effigies we tried solving the issue by updating the traits in CAT12SegmentInputSpec to the dafaults from the latest CAT12 version. In this version we either set the atlases to 1 that we want to use for ROI processing, or to 0 if we don't want it. However, there is also the option to say in advance, that we don't want any ROI processing and in that case in the Matlab GUI all of the Atlases vanish, because they are no longer relevant. This is when a new trait comes in jobs{1}.spm.tools.cat.estwrite.output.ROImenu.noROI = struct([]);
So we are currently trying to define this new trait in InputSpec, but how do we define a trait that when translated to Matlab code will be of type struct and will contain an empty list? In python the options I can think of are only List, Dict or Tuple.

JailanOweda pushed a commit to JailanOweda/nipype that referenced this issue Jul 1, 2024
effigies pushed a commit to JailanOweda/nipype that referenced this issue Oct 6, 2024
effigies pushed a commit to JailanOweda/nipype that referenced this issue Oct 6, 2024
…ted if statements for when no surface or ROI estimations are desired
effigies pushed a commit to JailanOweda/nipype that referenced this issue Oct 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants