Skip to content

Commit 9f2e498

Browse files
committed
Merge remote-tracking branch 'upstream/master' into dcm2nii
2 parents 19c23ca + f6ae4e4 commit 9f2e498

16 files changed

+346
-621
lines changed

CHANGES

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Next release
2828
* FIX: Correct linking/copying fallback behavior (https://github.com/nipy/nipype/pull/1391)
2929
* ENH: Nipype workflow and interfaces for FreeSurfer's recon-all (https://github.com/nipy/nipype/pull/1326)
3030
* FIX: Permit relative path for concatenated_file input to Concatenate() (https://github.com/nipy/nipype/pull/1411)
31+
* ENH: Makes ReconAll workflow backwards compatible with FreeSurfer 5.3.0 (https://github.com/nipy/nipype/pull/1434)
3132

3233
Release 0.11.0 (September 15, 2015)
3334
============

nipype/interfaces/freesurfer/model.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -752,8 +752,9 @@ def _list_outputs(self):
752752

753753
def _format_arg(self, name, spec, value):
754754
if name in ('summary_file', 'avgwf_txt_file'):
755-
if not os.path.isabs(value):
756-
value = os.path.join('.', value)
755+
if not isinstance(value, bool):
756+
if not os.path.isabs(value):
757+
value = os.path.join('.', value)
757758
if name in ['avgwf_txt_file', 'avgwf_file', 'sf_avg_file']:
758759
if isinstance(value, bool):
759760
fname = self._list_outputs()[name]
@@ -779,7 +780,7 @@ class SegStatsReconAllInputSpec(SegStatsInputSpec):
779780
# implicit
780781
ribbon = traits.File(mandatory=True, exists=True,
781782
desc="Input file mri/ribbon.mgz")
782-
presurf_seg = File(mandatory=True, exists=True,
783+
presurf_seg = File(exists=True,
783784
desc="Input segmentation volume")
784785
transform = File(mandatory=True, exists=True,
785786
desc="Input transform file")
@@ -795,6 +796,8 @@ class SegStatsReconAllInputSpec(SegStatsInputSpec):
795796
desc="Input file must be <subject_id>/surf/lh.pial")
796797
rh_pial = File(mandatory=True, exists=True,
797798
desc="Input file must be <subject_id>/surf/rh.pial")
799+
aseg = File(exists=True,
800+
desc="Mandatory implicit input in 5.3")
798801
copy_inputs = traits.Bool(desc="If running as a node, set this to True " +
799802
"otherwise, this will copy the implicit inputs " +
800803
"to the node directory.")
@@ -858,7 +861,7 @@ def run(self, **inputs):
858861
copy2subjdir(self, self.inputs.lh_white,
859862
'surf', 'lh.white')
860863
copy2subjdir(self, self.inputs.rh_white,
861-
'Surf', 'Rh.White')
864+
'surf', 'rh.white')
862865
copy2subjdir(self, self.inputs.lh_pial,
863866
'surf', 'lh.pial')
864867
copy2subjdir(self, self.inputs.rh_pial,
@@ -867,12 +870,13 @@ def run(self, **inputs):
867870
'mri', 'ribbon.mgz')
868871
copy2subjdir(self, self.inputs.presurf_seg,
869872
'mri', 'aseg.presurf.mgz')
873+
copy2subjdir(self, self.inputs.aseg,
874+
'mri', 'aseg.mgz')
870875
copy2subjdir(self, self.inputs.transform,
871876
os.path.join('mri', 'transforms'),
872877
'talairach.xfm')
873878
copy2subjdir(self, self.inputs.in_intensity, 'mri')
874-
if isdefined(self.inputs.brainmask_file):
875-
copy2subjdir(self, self.inputs.brainmask_file, 'mri')
879+
copy2subjdir(self, self.inputs.brainmask_file, 'mri')
876880
return super(SegStatsReconAll, self).run(**inputs)
877881

878882

nipype/interfaces/freesurfer/tests/test_auto_Aparc2Aseg.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ def test_Aparc2Aseg_inputs():
1919
environ=dict(nohash=True,
2020
usedefault=True,
2121
),
22+
filled=dict(),
2223
hypo_wm=dict(argstr='--hypo-as-wm',
2324
mandatory=False,
2425
),

nipype/interfaces/freesurfer/tests/test_auto_Curvature.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ def test_Curvature_inputs():
1919
usedefault=True,
2020
),
2121
in_file=dict(argstr='%s',
22+
copyfile=True,
2223
mandatory=True,
2324
position=-2,
2425
),

nipype/interfaces/freesurfer/tests/test_auto_MakeSurfaces.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ def test_MakeSurfaces_inputs():
3535
in_orig=dict(argstr='-orig %s',
3636
mandatory=True,
3737
),
38+
in_white=dict(),
3839
in_wm=dict(mandatory=True,
3940
),
4041
longitudinal=dict(argstr='-long',
@@ -66,6 +67,8 @@ def test_MakeSurfaces_inputs():
6667
subjects_dir=dict(),
6768
terminal_output=dict(nohash=True,
6869
),
70+
white=dict(argstr='-white %s',
71+
),
6972
white_only=dict(argstr='-whiteonly',
7073
mandatory=False,
7174
),

nipype/interfaces/freesurfer/tests/test_auto_SegStatsReconAll.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ def test_SegStatsReconAll_inputs():
1010
),
1111
args=dict(argstr='%s',
1212
),
13+
aseg=dict(),
1314
avgwf_file=dict(argstr='--avgwfvol %s',
1415
),
1516
avgwf_txt_file=dict(argstr='--avgwf %s',
@@ -85,8 +86,7 @@ def test_SegStatsReconAll_inputs():
8586
),
8687
partial_volume_file=dict(argstr='--pv %s',
8788
),
88-
presurf_seg=dict(mandatory=True,
89-
),
89+
presurf_seg=dict(),
9090
rh_orig_nofix=dict(mandatory=True,
9191
),
9292
rh_pial=dict(mandatory=True,

nipype/interfaces/freesurfer/tests/test_auto_VolumeMask.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
def test_VolumeMask_inputs():
77
input_map = dict(args=dict(argstr='%s',
88
),
9+
aseg=dict(xor=['in_aseg'],
10+
),
911
copy_inputs=dict(mandatory=False,
1012
),
1113
environ=dict(nohash=True,
@@ -16,6 +18,7 @@ def test_VolumeMask_inputs():
1618
),
1719
in_aseg=dict(argstr='--aseg_name %s',
1820
mandatory=False,
21+
xor=['aseg'],
1922
),
2023
left_ribbonlabel=dict(argstr='--label_left_ribbon %d',
2124
mandatory=True,

nipype/interfaces/freesurfer/utils.py

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,30 @@
3535

3636

3737
def copy2subjdir(cls, in_file, folder=None, basename=None, subject_id=None):
38+
"""Method to copy an input to the subjects directory"""
39+
# check that the input is defined
40+
if not isdefined(in_file):
41+
return in_file
42+
# check that subjects_dir is defined
3843
if isdefined(cls.inputs.subjects_dir):
3944
subjects_dir = cls.inputs.subjects_dir
4045
else:
41-
subjects_dir = os.getcwd()
46+
subjects_dir = os.getcwd() #if not use cwd
47+
# check for subject_id
4248
if not subject_id:
4349
if isdefined(cls.inputs.subject_id):
4450
subject_id = cls.inputs.subject_id
4551
else:
46-
subject_id = 'subject_id'
52+
subject_id = 'subject_id' #default
53+
# check for basename
4754
if basename == None:
4855
basename = os.path.basename(in_file)
56+
# check which folder to put the file in
4957
if folder != None:
5058
out_dir = os.path.join(subjects_dir, subject_id, folder)
5159
else:
5260
out_dir = os.path.join(subjects_dir, subject_id)
61+
# make the output folder if it does not exist
5362
if not os.path.isdir(out_dir):
5463
os.makedirs(out_dir)
5564
out_file = os.path.join(out_dir, basename)
@@ -58,7 +67,7 @@ def copy2subjdir(cls, in_file, folder=None, basename=None, subject_id=None):
5867
return out_file
5968

6069
def createoutputdirs(outputs):
61-
"""create an output directories. If not created, some freesurfer interfaces fail"""
70+
"""create all output directories. If not created, some freesurfer interfaces fail"""
6271
for output in outputs.itervalues():
6372
dirname = os.path.dirname(output)
6473
if not os.path.isdir(dirname):
@@ -1867,6 +1876,7 @@ class MakeSurfacesInputSpec(FSTraitedSpec):
18671876
in_filled = File(exists=True, mandatory=True,
18681877
desc="Implicit input file filled.mgz")
18691878
# optional
1879+
in_white = File(exists=True, desc="Implicit input that is sometimes used")
18701880
in_label = File(exists=True, mandatory=False, xor=['noaparc'],
18711881
desc="Implicit input label/<hemisphere>.aparc.annot")
18721882
orig_white = File(argstr="-orig_white %s", exists=True, mandatory=False,
@@ -1893,6 +1903,8 @@ class MakeSurfacesInputSpec(FSTraitedSpec):
18931903
argstr="-max %.1f", desc="No documentation (used for longitudinal processing)")
18941904
longitudinal = traits.Bool(
18951905
argstr="-long", desc="No documentation (used for longitudinal processing)")
1906+
white = traits.String(argstr="-white %s",
1907+
desc="White surface name")
18961908
copy_inputs = traits.Bool(mandatory=False,
18971909
desc="If running as a node, set this to True." +
18981910
"This will copy the input files to the node " +
@@ -1947,15 +1959,15 @@ def run(self, **inputs):
19471959
folder='mri', basename='wm.mgz')
19481960
copy2subjdir(self, self.inputs.in_filled,
19491961
folder='mri', basename='filled.mgz')
1962+
copy2subjdir(self, self.inputs.in_white,
1963+
'surf', '{0}.white'.format(self.inputs.hemisphere))
19501964
for originalfile in [self.inputs.in_aseg,
19511965
self.inputs.in_T1]:
1952-
if isdefined(originalfile):
1953-
copy2subjdir(self, originalfile, folder='mri')
1966+
copy2subjdir(self, originalfile, folder='mri')
19541967
for originalfile in [self.inputs.orig_white,
19551968
self.inputs.orig_pial,
19561969
self.inputs.in_orig]:
1957-
if isdefined(originalfile):
1958-
copy2subjdir(self, originalfile, folder='surf')
1970+
copy2subjdir(self, originalfile, folder='surf')
19591971
if isdefined(self.inputs.in_label):
19601972
copy2subjdir(self, self.inputs.in_label, 'label',
19611973
'{0}.aparc.annot'.format(self.inputs.hemisphere))
@@ -1972,9 +1984,11 @@ def _format_arg(self, name, spec, value):
19721984
basename = os.path.basename(value)
19731985
# whent the -mgz flag is specified, it assumes the mgz extension
19741986
if self.inputs.mgz:
1975-
prefix = basename.rstrip('.mgz')
1987+
prefix = os.path.splitext(basename)[0]
19761988
else:
19771989
prefix = basename
1990+
if prefix == 'aseg':
1991+
return # aseg is already the default
19781992
return spec.argstr % prefix
19791993
elif name in ['orig_white', 'orig_pial']:
19801994
# these inputs do take full file paths or even basenames
@@ -2011,8 +2025,8 @@ def _list_outputs(self):
20112025
dest_dir, str(self.inputs.hemisphere) + '.area')
20122026
# Something determines when a pial surface and thickness file is generated
20132027
# but documentation doesn't say what.
2014-
# The orig_pial flag is just a guess
2015-
if isdefined(self.inputs.orig_pial):
2028+
# The orig_pial input is just a guess
2029+
if isdefined(self.inputs.orig_pial) or self.inputs.white == 'NOWRITE':
20162030
outputs["out_curv"] = outputs["out_curv"] + ".pial"
20172031
outputs["out_area"] = outputs["out_area"] + ".pial"
20182032
outputs["out_pial"] = os.path.join(
@@ -2029,7 +2043,7 @@ def _list_outputs(self):
20292043

20302044
class CurvatureInputSpec(FSTraitedSpec):
20312045
in_file = File(argstr="%s", position=-2, mandatory=True, exists=True,
2032-
desc="Input file for Curvature")
2046+
copyfile=True, desc="Input file for Curvature")
20332047
# optional
20342048
threshold = traits.Float(
20352049
argstr="-thresh %.3f", mandatory=False, desc="Undocumented input threshold")
@@ -2073,7 +2087,6 @@ def _format_arg(self, name, spec, value):
20732087
if self.inputs.copy_input:
20742088
if name == 'in_file':
20752089
basename = os.path.basename(value)
2076-
shutil.copy(value, basename)
20772090
return spec.argstr % basename
20782091
return super(Curvature, self)._format_arg(name, spec, value)
20792092

@@ -2301,11 +2314,16 @@ class VolumeMaskInputSpec(FSTraitedSpec):
23012314
desc="Implicit input left white matter surface")
23022315
rh_white = File(mandatory=True, exists=True,
23032316
desc="Implicit input right white matter surface")
2317+
aseg = File(exists=True,
2318+
xor=['in_aseg'],
2319+
desc="Implicit aseg.mgz segmentation. " +
2320+
"Specify a different aseg by using the 'in_aseg' input.")
23042321
subject_id = traits.String('subject_id', usedefault=True,
23052322
position=-1, argstr="%s", mandatory=True,
23062323
desc="Subject being processed")
23072324
# optional
2308-
in_aseg = File(argstr="--aseg_name %s", mandatory=False, exists=True,
2325+
in_aseg = File(argstr="--aseg_name %s", mandatory=False,
2326+
exists=True, xor=['aseg'],
23092327
desc="Input aseg file for VolumeMask")
23102328
save_ribbon = traits.Bool(argstr="--save_ribbon", mandatory=False,
23112329
desc="option to save just the ribbon for the " +
@@ -2364,6 +2382,8 @@ def run(self, **inputs):
23642382
copy2subjdir(self, self.inputs.lh_white, 'surf', 'lh.white')
23652383
copy2subjdir(self, self.inputs.rh_white, 'surf', 'rh.white')
23662384
copy2subjdir(self, self.inputs.in_aseg, 'mri')
2385+
copy2subjdir(self, self.inputs.aseg, 'mri', 'aseg.mgz')
2386+
23672387
return super(VolumeMask, self).run(**inputs)
23682388

23692389
def _format_arg(self, name, spec, value):
@@ -2726,6 +2746,8 @@ class Aparc2AsegInputSpec(FSTraitedSpec):
27262746
rh_annotation = File(mandatory=True, exists=True,
27272747
desc="Input file must be <subject_id>/label/rh.aparc.annot")
27282748
# optional
2749+
filled = File(exists=True,
2750+
desc="Implicit input filled file. Only required with FS v5.3.")
27292751
aseg = File(argstr="--aseg %s", mandatory=False, exists=True,
27302752
desc="Input aseg file")
27312753
volmask = traits.Bool(argstr="--volmask", mandatory=False,
@@ -2808,6 +2830,7 @@ def run(self, **inputs):
28082830
copy2subjdir(self, self.inputs.rh_ribbon, 'mri', 'rh.ribbon.mgz')
28092831
copy2subjdir(self, self.inputs.ribbon, 'mri', 'ribbon.mgz')
28102832
copy2subjdir(self, self.inputs.aseg, 'mri')
2833+
copy2subjdir(self, self.inputs.filled, 'mri', 'filled.mgz')
28112834
copy2subjdir(self, self.inputs.lh_annotation, 'label')
28122835
copy2subjdir(self, self.inputs.rh_annotation, 'label')
28132836

@@ -2816,7 +2839,8 @@ def run(self, **inputs):
28162839
def _format_arg(self, name, spec, value):
28172840
if name == 'aseg':
28182841
# aseg does not take a full filename
2819-
return spec.argstr % os.path.basename(value).replace('.mgz', '')
2842+
basename = os.path.basename(value).replace('.mgz', '')
2843+
return spec.argstr % basename
28202844
elif name == 'out_file':
28212845
return spec.argstr % os.path.abspath(value)
28222846

nipype/pipeline/plugins/sge.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def is_initializing(self):
6060
return self._job_queue_state == "initializing"
6161

6262
def is_zombie(self):
63-
return self._job_queue_state == "zombie"
63+
return self._job_queue_state == "zombie" or self._job_queue_state == "finished"
6464

6565
def is_running(self):
6666
return self._job_queue_state == "running"

0 commit comments

Comments
 (0)