Description
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.