From 166f20966887fefa7d8be6c26cf1ff1a9ebda41a Mon Sep 17 00:00:00 2001 From: akeshavan Date: Mon, 4 Apr 2016 14:14:37 -0700 Subject: [PATCH 01/72] fix: sge plugin - no zombies at ucsf --- nipype/pipeline/plugins/sge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/pipeline/plugins/sge.py b/nipype/pipeline/plugins/sge.py index 547a3cbbb8..bbe5be9db8 100644 --- a/nipype/pipeline/plugins/sge.py +++ b/nipype/pipeline/plugins/sge.py @@ -60,7 +60,7 @@ def is_initializing(self): return self._job_queue_state == "initializing" def is_zombie(self): - return self._job_queue_state == "zombie" + return self._job_queue_state == "zombie" or self._job_queue_state == "finished" def is_running(self): return self._job_queue_state == "running" From eea0b9aaf7e94327f8b97702745f318256592b10 Mon Sep 17 00:00:00 2001 From: Alexandre Manhaes Savio Date: Thu, 7 Apr 2016 14:05:45 +0200 Subject: [PATCH 02/72] add nipype_crash_search script --- bin/nipype_crash_search.py | 76 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100755 bin/nipype_crash_search.py diff --git a/bin/nipype_crash_search.py b/bin/nipype_crash_search.py new file mode 100755 index 0000000000..068e5d600a --- /dev/null +++ b/bin/nipype_crash_search.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +"""Search for tracebacks inside a folder of nipype crash +log files that match a given regular expression. + +Examples: +nipype_crash_search -d nipype/wd/log -r '.*subject123.*' +""" +import re +import os.path as op +from glob import glob + +from traits.trait_errors import TraitError +from nipype.utils.filemanip import loadcrash + + +def load_pklz_traceback(crash_filepath): + """ Return the traceback message in the given crash file.""" + try: + data = loadcrash(crash_filepath) + except TraitError as te: + return str(te) + except: + raise + else: + return '\n'.join(data['traceback']) + + +def iter_tracebacks(logdir): + """ Return an iterator over each file path and + traceback field inside `logdir`. + Parameters + ---------- + logdir: str + Path to the log folder. + + field: str + Field name to be read from the crash file. + + Yields + ------ + path_file: str + + traceback: str + """ + crash_files = sorted(glob(op.join(logdir, '*.pkl*'))) + + for cf in crash_files: + yield cf, load_pklz_traceback(cf) + + +def display_crash_search(logdir, regex): + rex = re.compile(regex, re.IGNORECASE) + for file, trace in iter_tracebacks(logdir): + if rex.search(trace): + print("-" * len(file)) + print(file) + print("-" * len(file)) + print(trace) + + +if __name__ == "__main__": + from argparse import ArgumentParser, RawTextHelpFormatter + defstr = ' (default %(default)s)' + parser = ArgumentParser(prog='nipype_crash_search', + description=__doc__, + formatter_class=RawTextHelpFormatter) + parser.add_argument('-l','--logdir', type=str, dest='logdir', + action="store", default=None, + help='The working directory log file.' + defstr) + parser.add_argument('-r', '--regex', dest='regex', + default='*', + help='Regular expression to be searched in each traceback.' + defstr) + + args = parser.parse_args() + + display_crash_search(args.logdir, args.regex) From 98012c81e28472c101df8cf2bd82911c9bdf0c8d Mon Sep 17 00:00:00 2001 From: akeshavan Date: Mon, 11 Apr 2016 14:49:48 -0700 Subject: [PATCH 03/72] fix: removed list_outputs because it isn't needed --- nipype/interfaces/freesurfer/utils.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/nipype/interfaces/freesurfer/utils.py b/nipype/interfaces/freesurfer/utils.py index 1b4b5e3d15..6edb1399e9 100644 --- a/nipype/interfaces/freesurfer/utils.py +++ b/nipype/interfaces/freesurfer/utils.py @@ -527,11 +527,6 @@ class ApplyMask(FSCommand): input_spec = ApplyMaskInputSpec output_spec = ApplyMaskOutputSpec - def _list_outputs(self): - outputs = self._outputs().get() - outputs["out_file"] = os.path.abspath(self.inputs.out_file) - return outputs - class SurfaceSnapshotsInputSpec(FSTraitedSpec): From 66069cd6a622ed71a5abe2b7c3ec216900a957b9 Mon Sep 17 00:00:00 2001 From: akeshavan Date: Mon, 11 Apr 2016 15:26:29 -0700 Subject: [PATCH 04/72] doc: make check-before-commit --- nipype/workflows/smri/freesurfer/recon.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/recon.py b/nipype/workflows/smri/freesurfer/recon.py index c9206812f3..b574314f35 100644 --- a/nipype/workflows/smri/freesurfer/recon.py +++ b/nipype/workflows/smri/freesurfer/recon.py @@ -82,7 +82,7 @@ def link_masks(subjects_dir, subject_id): def create_reconall_workflow(name="ReconAll", plugin_args=None, recoding_file=None): """Creates the ReconAll workflow in nipype. - + Example ------- >>> from nipype.workflows.smri.freesurfer import create_skullstripped_recon_flow @@ -200,7 +200,7 @@ def checkarg(arg, default): 'lookup_table', 'wm_lookup_table', 'awk_file'] - + config_node = pe.Node(niu.Function(params, params, setconfig), @@ -509,7 +509,7 @@ def completemethod(datasinked_files, subject_id): reconall.connect([(datasink, completion, [('out_file', 'datasinked_files')]), (inputspec, completion, [('subject_id', 'subject_id')]), (completion, postds_outputspec, [('subject_id', 'subject_id')])]) - + #### Workflow additions go here if recoding_file: From 9fd5187fcd71f20f42f621473df404541b94f3f7 Mon Sep 17 00:00:00 2001 From: akeshavan Date: Mon, 11 Apr 2016 16:14:44 -0700 Subject: [PATCH 05/72] doc: make check-before-commit --- nipype/workflows/smri/freesurfer/recon.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/recon.py b/nipype/workflows/smri/freesurfer/recon.py index c9206812f3..b574314f35 100644 --- a/nipype/workflows/smri/freesurfer/recon.py +++ b/nipype/workflows/smri/freesurfer/recon.py @@ -82,7 +82,7 @@ def link_masks(subjects_dir, subject_id): def create_reconall_workflow(name="ReconAll", plugin_args=None, recoding_file=None): """Creates the ReconAll workflow in nipype. - + Example ------- >>> from nipype.workflows.smri.freesurfer import create_skullstripped_recon_flow @@ -200,7 +200,7 @@ def checkarg(arg, default): 'lookup_table', 'wm_lookup_table', 'awk_file'] - + config_node = pe.Node(niu.Function(params, params, setconfig), @@ -509,7 +509,7 @@ def completemethod(datasinked_files, subject_id): reconall.connect([(datasink, completion, [('out_file', 'datasinked_files')]), (inputspec, completion, [('subject_id', 'subject_id')]), (completion, postds_outputspec, [('subject_id', 'subject_id')])]) - + #### Workflow additions go here if recoding_file: From 34df67cb4d75525f9173cbadf220ef06ff3810d5 Mon Sep 17 00:00:00 2001 From: Chris Gorgolewski Date: Mon, 11 Apr 2016 19:00:59 -0700 Subject: [PATCH 06/72] Added Gitter Sidecar --- doc/_templates/layout.html | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html index 8a3b08697e..a8de8d176b 100644 --- a/doc/_templates/layout.html +++ b/doc/_templates/layout.html @@ -14,6 +14,12 @@ ga('create', 'UA-339450-7', 'nipy.org/nipype'); ga('send', 'pageview'); + + {% endblock %} {% block header %} From dba3270e98d12ba65b4030b9315d7ca63ccb7d79 Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Tue, 12 Apr 2016 13:15:51 -0400 Subject: [PATCH 07/72] REF: Simplify checkT1s * Use nibabel instead of SimpleITK to determine image shape * Do not convert .mgz to .nii * Simplify error checking and origvol_names with comprehensions * PEP8 cleanup in/around checkT1s --- .../workflows/smri/freesurfer/autorecon1.py | 57 +++++++------------ 1 file changed, 20 insertions(+), 37 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon1.py b/nipype/workflows/smri/freesurfer/autorecon1.py index bc4fb8bff2..b77b65465c 100644 --- a/nipype/workflows/smri/freesurfer/autorecon1.py +++ b/nipype/workflows/smri/freesurfer/autorecon1.py @@ -6,53 +6,36 @@ from nipype.interfaces.freesurfer import * from .utils import copy_file, copy_files + def checkT1s(T1_files, cw256=False): """Verifying size of inputs and setting workflow parameters""" - import SimpleITK as sitk - import os import sys - # check that the files are in a list - if not type(T1_files) == list: - T1_files = [T1_files] + import nibabel as nib + from nipype.utils.filemanip import filename_to_list + + T1_files = filename_to_list(T1_files) if len(T1_files) == 0: print("ERROR: No T1's Given") sys.exit(-1) - for i, t1 in enumerate(T1_files): - if t1.endswith(".mgz"): - # convert input fs files to NIFTI - convert = MRIConvert() - convert.inputs.in_file = t1 - convert.inputs.out_file = os.path.abspath(os.path.basename(t1).replace('.mgz', '.nii.gz')) - convert.run() - T1_files[i] = convert.inputs.out_file - size = None - origvol_names = list() - for i, t1 in enumerate(T1_files): - # assign an input number - file_num = str(i + 1) - while len(file_num) < 3: - file_num = '0' + file_num - origvol_names.append("{0}.mgz".format(file_num)) - # check the size of the image - img = sitk.ReadImage(t1) - if not size: - size = img.GetSize() - elif size != img.GetSize(): - print("ERROR: T1s not the same size. Cannot process {0} {1} together".format(T1_files[0], - otherFilename)) + + shape = nib.load(T1_files[0]).shape + for t1 in T1_files[1:]: + if nib.load(t1).shape != shape: + print("ERROR: T1s not the same size. Cannot process {0} and {1} " + "together".format(T1_files[0], t1)) sys.exit(-1) + + origvol_names = ["{0:03d}.mgz".format(i + 1) for i in range(len(T1_files))] + # check if cw256 is set to crop the images if size is larger than 256 - if not cw256: - for dim in size: - if dim > 256: - print("Setting MRI Convert to crop images to 256 FOV") - cw256 = True - if len(T1_files) > 1: - resample_type = 'cubic' - else: - resample_type = 'interpolate' + if not cw256 and any(dim > 256 for dim in shape): + print("Setting MRI Convert to crop images to 256 FOV") + cw256 = True + + resample_type = 'cubic' if len(T1_files) > 1 else 'interpolate' return T1_files, cw256, resample_type, origvol_names + def create_AutoRecon1(name="AutoRecon1", longitudinal=False, field_strength='1.5T', custom_atlas=None, plugin_args=None): """Creates the AutoRecon1 workflow in nipype. From 0fd5842183233687f0dc62cf4fd66d43698cea13 Mon Sep 17 00:00:00 2001 From: akeshavan Date: Tue, 12 Apr 2016 12:42:53 -0700 Subject: [PATCH 08/72] fix: segstats avgwf_txt_file can be a bool without error --- nipype/interfaces/freesurfer/model.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nipype/interfaces/freesurfer/model.py b/nipype/interfaces/freesurfer/model.py index 607586d6f6..2980f147d8 100644 --- a/nipype/interfaces/freesurfer/model.py +++ b/nipype/interfaces/freesurfer/model.py @@ -752,8 +752,9 @@ def _list_outputs(self): def _format_arg(self, name, spec, value): if name in ('summary_file', 'avgwf_txt_file'): - if not os.path.isabs(value): - value = os.path.join('.', value) + if not isinstance(value, bool): + if not os.path.isabs(value): + value = os.path.join('.', value) if name in ['avgwf_txt_file', 'avgwf_file', 'sf_avg_file']: if isinstance(value, bool): fname = self._list_outputs()[name] From 2ce38f4d5e92927bc4ed687f59fc537510b303ab Mon Sep 17 00:00:00 2001 From: David Ellis Date: Fri, 1 Apr 2016 09:21:04 -0500 Subject: [PATCH 09/72] FIX: Fixes a few flags in for FreeSurfer 5.3 --- .../workflows/smri/freesurfer/autorecon1.py | 25 ++++++---------- .../workflows/smri/freesurfer/autorecon3.py | 4 +-- nipype/workflows/smri/freesurfer/ba_maps.py | 13 +++++++-- nipype/workflows/smri/freesurfer/recon.py | 29 +++++++++++++++++-- 4 files changed, 48 insertions(+), 23 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon1.py b/nipype/workflows/smri/freesurfer/autorecon1.py index b77b65465c..dca938c4c2 100644 --- a/nipype/workflows/smri/freesurfer/autorecon1.py +++ b/nipype/workflows/smri/freesurfer/autorecon1.py @@ -35,9 +35,8 @@ def checkT1s(T1_files, cw256=False): resample_type = 'cubic' if len(T1_files) > 1 else 'interpolate' return T1_files, cw256, resample_type, origvol_names - -def create_AutoRecon1(name="AutoRecon1", longitudinal=False, field_strength='1.5T', - custom_atlas=None, plugin_args=None): +def create_AutoRecon1(name="AutoRecon1", longitudinal=False, distance=200, + custom_atlas=None, plugin_args=None, shrink=2): """Creates the AutoRecon1 workflow in nipype. Inputs:: @@ -238,19 +237,13 @@ def createTemplate(in_files, out_file): bias_correction = pe.Node(MNIBiasCorrection(), name="Bias_correction") bias_correction.inputs.iterations = 1 bias_correction.inputs.protocol_iterations = 1000 - if field_strength == '3T': - # 3T params from Zheng, Chee, Zagorodnov 2009 NeuroImage paper - # "Improvement of brain segmentation accuracy by optimizing - # non-uniformity correction using N3" - # namely specifying iterations, proto-iters and distance: - bias_correction.inputs.distance = 50 - else: - # 1.5T default - bias_correction.inputs.distance = 200 - # per c.larsen, decrease convergence threshold (default is 0.001) - bias_correction.inputs.stop = 0.0001 - # per c.larsen, decrease shrink parameter: finer sampling (default is 4) - bias_correction.inputs.shrink = 2 + bias_correction.inputs.distance = distance + if stop: + # per c.larsen, decrease convergence threshold (default is 0.001) + bias_correction.inputs.stop = stop + if shrink: + # per c.larsen, decrease shrink parameter: finer sampling (default is 4) + bias_correction.inputs.shrink = shrink # add the mask, as per c.larsen, bias-field correction is known to work # much better when the brain area is properly masked, in this case by # brainmask.mgz. diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index ffc0eec7b9..bf383231f5 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -8,7 +8,7 @@ from nipype.interfaces.io import DataGrabber def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, - th3=True): + th3=True, exvivo=True): # AutoRecon3 # Workflow @@ -705,7 +705,7 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, ]) # add brodman area maps to the workflow - ba_WF, ba_outputs = create_ba_maps_wf(th3=th3) + ba_WF, ba_outputs = create_ba_maps_wf(th3=th3, exvivo=exvivo) ar3_wf.connect([(ar3_lh_wf1, ba_WF, [('outputspec.sphere_reg', 'inputspec.lh_sphere_reg'), ('outputspec.thickness_pial', 'inputspec.lh_thickness'), diff --git a/nipype/workflows/smri/freesurfer/ba_maps.py b/nipype/workflows/smri/freesurfer/ba_maps.py index 337e1f40cb..8e39726ece 100644 --- a/nipype/workflows/smri/freesurfer/ba_maps.py +++ b/nipype/workflows/smri/freesurfer/ba_maps.py @@ -6,7 +6,7 @@ from nipype.interfaces.io import DataGrabber from nipype.interfaces.utility import Merge -def create_ba_maps_wf(name="Brodmann_Area_Maps", th3=True): +def create_ba_maps_wf(name="Brodmann_Area_Maps", th3=True, exvivo=True): # Brodmann Area Maps (BA Maps) and Hinds V1 Atlas inputs = ['lh_sphere_reg', 'rh_sphere_reg', @@ -64,13 +64,20 @@ def create_ba_maps_wf(name="Brodmann_Area_Maps", th3=True): out_files = list() if threshold: for label in labels: - out_file = '{0}.{1}_exvivo.thresh.label'.format(hemisphere, label) + if exvivo: + out_file = '{0}.{1}_exvivo.thresh.label'.format(hemisphere, label) + else: + out_file = '{0}.{1}.thresh.label'.format(hemisphere, label) out_files.append(out_file) field_template[label] = 'label/' + out_file node_name = 'BA_Maps_' + hemisphere + '_Tresh' else: for label in labels: - out_file = '{0}.{1}_exvivo.label'.format(hemisphere, label) + if exvivo: + out_file = '{0}.{1}_exvivo.label'.format(hemisphere, label) + else: + out_file = '{0}.{1}.label'.format(hemisphere, label) + out_files.append(out_file) field_template[label] = 'label/' + out_file node_name = 'BA_Maps_' + hemisphere diff --git a/nipype/workflows/smri/freesurfer/recon.py b/nipype/workflows/smri/freesurfer/recon.py index b574314f35..376f0b695e 100644 --- a/nipype/workflows/smri/freesurfer/recon.py +++ b/nipype/workflows/smri/freesurfer/recon.py @@ -4,7 +4,7 @@ from .autorecon1 import create_AutoRecon1 from .autorecon2 import create_AutoRecon2 from .autorecon3 import create_AutoRecon3 -from ....interfaces.freesurfer import AddXFormToHeader +from ....interfaces.freesurfer import AddXFormToHeader, Info from ....interfaces.io import DataSink from .utils import getdefaultconfig @@ -135,6 +135,30 @@ def create_reconall_workflow(name="ReconAll", plugin_args=None, run_without_submitting=True, name='inputspec') + # check freesurfer version and set parameters + fs_version_full = Info.version() + elif 'v6.0' in fs_version_full or 'dev' in fs_version_full: + # assuming that dev is 6.0 + fs_version = '6.0' + th3 = True + shrink = 2 + distance = 200 # 3T should be 50 + exvivo = True + else: + # 5.3 is default + if 'v5.3' in fs_version_full: + fs_version = '5.3' + else: + fs_vesion = fs_version_full.split('-')[-1] + print("Warning: Workflow may not work properly if FREESURFER_HOME " + + "environmental variable is not set or if you are using an older " + + "version of FreeSurfer") + th3 = False + shrink = None + exvivo = False + distance = 50 + stop = None + def setconfig(reg_template=None, reg_template_withskull=None, lh_atlas=None, @@ -232,7 +256,8 @@ def checkarg(arg, default): ('outputspec.talairach', 'inputspec.transform'), ('outputspec.orig', 'inputspec.orig')])]) # create AutoRecon3 - ar3_wf, ar3_outputs = create_AutoRecon3(plugin_args=plugin_args, th3=True) + ar3_wf, ar3_outputs = create_AutoRecon3(plugin_args=plugin_args, th3=th3, + exvivo=exvivo) # connect inputs for AutoRecon3 reconall.connect([(config_node, ar3_wf, [('lh_atlas', 'inputspec.lh_atlas'), ('rh_atlas', 'inputspec.rh_atlas'), From 7a43049a8207ee259019bb0798aea92f14ae3416 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Fri, 1 Apr 2016 09:25:28 -0500 Subject: [PATCH 10/72] ENH: Print FS version. --- nipype/workflows/smri/freesurfer/recon.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/recon.py b/nipype/workflows/smri/freesurfer/recon.py index 376f0b695e..efd2583f16 100644 --- a/nipype/workflows/smri/freesurfer/recon.py +++ b/nipype/workflows/smri/freesurfer/recon.py @@ -139,7 +139,7 @@ def create_reconall_workflow(name="ReconAll", plugin_args=None, fs_version_full = Info.version() elif 'v6.0' in fs_version_full or 'dev' in fs_version_full: # assuming that dev is 6.0 - fs_version = '6.0' + fs_version = 'v6.0' th3 = True shrink = 2 distance = 200 # 3T should be 50 @@ -147,7 +147,7 @@ def create_reconall_workflow(name="ReconAll", plugin_args=None, else: # 5.3 is default if 'v5.3' in fs_version_full: - fs_version = '5.3' + fs_version = 'v5.3' else: fs_vesion = fs_version_full.split('-')[-1] print("Warning: Workflow may not work properly if FREESURFER_HOME " + @@ -158,7 +158,9 @@ def create_reconall_workflow(name="ReconAll", plugin_args=None, exvivo = False distance = 50 stop = None - + + print("FreeSurfer Version: {0}".format(fs_version)) + def setconfig(reg_template=None, reg_template_withskull=None, lh_atlas=None, From ee7ab69fbba33796c34cfade670d5d014268fbc5 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Fri, 1 Apr 2016 09:27:30 -0500 Subject: [PATCH 11/72] FIX: Fixes elif syntax error. --- nipype/workflows/smri/freesurfer/recon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/workflows/smri/freesurfer/recon.py b/nipype/workflows/smri/freesurfer/recon.py index efd2583f16..4646f90334 100644 --- a/nipype/workflows/smri/freesurfer/recon.py +++ b/nipype/workflows/smri/freesurfer/recon.py @@ -137,7 +137,7 @@ def create_reconall_workflow(name="ReconAll", plugin_args=None, # check freesurfer version and set parameters fs_version_full = Info.version() - elif 'v6.0' in fs_version_full or 'dev' in fs_version_full: + if 'v6.0' in fs_version_full or 'dev' in fs_version_full: # assuming that dev is 6.0 fs_version = 'v6.0' th3 = True From dc8fec34bb811df103f44c900f01dff5c53f6b91 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Fri, 1 Apr 2016 09:33:14 -0500 Subject: [PATCH 12/72] FIX: Adds stop and shrink to autorecon1. --- nipype/workflows/smri/freesurfer/autorecon1.py | 2 +- nipype/workflows/smri/freesurfer/recon.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon1.py b/nipype/workflows/smri/freesurfer/autorecon1.py index dca938c4c2..db26ea77d4 100644 --- a/nipype/workflows/smri/freesurfer/autorecon1.py +++ b/nipype/workflows/smri/freesurfer/autorecon1.py @@ -36,7 +36,7 @@ def checkT1s(T1_files, cw256=False): return T1_files, cw256, resample_type, origvol_names def create_AutoRecon1(name="AutoRecon1", longitudinal=False, distance=200, - custom_atlas=None, plugin_args=None, shrink=2): + custom_atlas=None, plugin_args=None, shrink=2, stop=0.0001): """Creates the AutoRecon1 workflow in nipype. Inputs:: diff --git a/nipype/workflows/smri/freesurfer/recon.py b/nipype/workflows/smri/freesurfer/recon.py index 4646f90334..2f6967e15b 100644 --- a/nipype/workflows/smri/freesurfer/recon.py +++ b/nipype/workflows/smri/freesurfer/recon.py @@ -143,6 +143,7 @@ def create_reconall_workflow(name="ReconAll", plugin_args=None, th3 = True shrink = 2 distance = 200 # 3T should be 50 + stop = 0.0001 exvivo = True else: # 5.3 is default @@ -155,9 +156,9 @@ def create_reconall_workflow(name="ReconAll", plugin_args=None, "version of FreeSurfer") th3 = False shrink = None - exvivo = False distance = 50 stop = None + exvivo = False print("FreeSurfer Version: {0}".format(fs_version)) @@ -236,7 +237,8 @@ def checkarg(arg, default): reconall.connect(inputspec, param, config_node, param) # create AutoRecon1 - ar1_wf, ar1_outputs = create_AutoRecon1(plugin_args=plugin_args) + ar1_wf, ar1_outputs = create_AutoRecon1(plugin_args=plugin_args, stop=stop, + distance=distance, shrink=shrink) # connect inputs for AutoRecon1 reconall.connect([(inputspec, ar1_wf, [('T1_files', 'inputspec.T1_files'), ('T2_file', 'inputspec.T2_file'), From c79f559dd9c78b4a7d3b1f8bdfbe2121626352a8 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Fri, 1 Apr 2016 09:46:13 -0500 Subject: [PATCH 13/72] FIX: Removes entorhinal BA maps for 5.3. --- nipype/workflows/smri/freesurfer/autorecon3.py | 3 ++- nipype/workflows/smri/freesurfer/ba_maps.py | 7 +++++-- nipype/workflows/smri/freesurfer/recon.py | 4 +++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index bf383231f5..7d64095ae2 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -705,7 +705,8 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, ]) # add brodman area maps to the workflow - ba_WF, ba_outputs = create_ba_maps_wf(th3=th3, exvivo=exvivo) + ba_WF, ba_outputs = create_ba_maps_wf(th3=th3, exvivo=exvivo, + entorhinal=entorhinal) ar3_wf.connect([(ar3_lh_wf1, ba_WF, [('outputspec.sphere_reg', 'inputspec.lh_sphere_reg'), ('outputspec.thickness_pial', 'inputspec.lh_thickness'), diff --git a/nipype/workflows/smri/freesurfer/ba_maps.py b/nipype/workflows/smri/freesurfer/ba_maps.py index 8e39726ece..c586bbb0ee 100644 --- a/nipype/workflows/smri/freesurfer/ba_maps.py +++ b/nipype/workflows/smri/freesurfer/ba_maps.py @@ -6,7 +6,8 @@ from nipype.interfaces.io import DataGrabber from nipype.interfaces.utility import Merge -def create_ba_maps_wf(name="Brodmann_Area_Maps", th3=True, exvivo=True): +def create_ba_maps_wf(name="Brodmann_Area_Maps", th3=True, exvivo=True, + entorhinal=True): # Brodmann Area Maps (BA Maps) and Hinds V1 Atlas inputs = ['lh_sphere_reg', 'rh_sphere_reg', @@ -55,7 +56,9 @@ def create_ba_maps_wf(name="Brodmann_Area_Maps", th3=True, exvivo=True): name="outputspec") labels = ["BA1", "BA2", "BA3a", "BA3b", "BA4a", "BA4p", "BA6", - "BA44", "BA45", "V1", "V2", "MT", "entorhinal", "perirhinal"] + "BA44", "BA45", "V1", "V2", "MT", "perirhinal"] + if entorhinal: + labels.append('entorhinal') for hemisphere in ['lh', 'rh']: for threshold in [True, False]: field_template = dict(sphere_reg='surf/{0}.sphere.reg'.format(hemisphere), diff --git a/nipype/workflows/smri/freesurfer/recon.py b/nipype/workflows/smri/freesurfer/recon.py index 2f6967e15b..a7791b49e8 100644 --- a/nipype/workflows/smri/freesurfer/recon.py +++ b/nipype/workflows/smri/freesurfer/recon.py @@ -145,6 +145,7 @@ def create_reconall_workflow(name="ReconAll", plugin_args=None, distance = 200 # 3T should be 50 stop = 0.0001 exvivo = True + entorhinal = True else: # 5.3 is default if 'v5.3' in fs_version_full: @@ -159,6 +160,7 @@ def create_reconall_workflow(name="ReconAll", plugin_args=None, distance = 50 stop = None exvivo = False + entorhinal = False print("FreeSurfer Version: {0}".format(fs_version)) @@ -261,7 +263,7 @@ def checkarg(arg, default): ('outputspec.orig', 'inputspec.orig')])]) # create AutoRecon3 ar3_wf, ar3_outputs = create_AutoRecon3(plugin_args=plugin_args, th3=th3, - exvivo=exvivo) + exvivo=exvivo, entorhinal=entorhinal) # connect inputs for AutoRecon3 reconall.connect([(config_node, ar3_wf, [('lh_atlas', 'inputspec.lh_atlas'), ('rh_atlas', 'inputspec.rh_atlas'), From bfa3c2995e4b7192886000925927710cd968c8f0 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Fri, 1 Apr 2016 09:51:27 -0500 Subject: [PATCH 14/72] FIX: Adds entorhinal to autorecon3 --- nipype/workflows/smri/freesurfer/autorecon3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index 7d64095ae2..d0dc354677 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -8,7 +8,7 @@ from nipype.interfaces.io import DataGrabber def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, - th3=True, exvivo=True): + th3=True, exvivo=True, entorhinal=True): # AutoRecon3 # Workflow From 291bafd9e6696c0be5adbf09e596f6a1f15a1a03 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Fri, 1 Apr 2016 10:04:04 -0500 Subject: [PATCH 15/72] FIX: Removes thresh.perirhinal from 5.3 --- nipype/workflows/smri/freesurfer/ba_maps.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nipype/workflows/smri/freesurfer/ba_maps.py b/nipype/workflows/smri/freesurfer/ba_maps.py index c586bbb0ee..6602fdeeb5 100644 --- a/nipype/workflows/smri/freesurfer/ba_maps.py +++ b/nipype/workflows/smri/freesurfer/ba_maps.py @@ -67,6 +67,9 @@ def create_ba_maps_wf(name="Brodmann_Area_Maps", th3=True, exvivo=True, out_files = list() if threshold: for label in labels: + if label == 'perirhinal' and entorhinal: + # versions < 6.0 do not use thresh.perirhinal + continue if exvivo: out_file = '{0}.{1}_exvivo.thresh.label'.format(hemisphere, label) else: From 4bd496236f553ec0b80da414247db941b2a0f44f Mon Sep 17 00:00:00 2001 From: David Ellis Date: Fri, 1 Apr 2016 10:13:28 -0500 Subject: [PATCH 16/72] FIX: Allows for changing of RB atlas --- nipype/workflows/smri/freesurfer/recon.py | 7 +++++-- nipype/workflows/smri/freesurfer/utils.py | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/recon.py b/nipype/workflows/smri/freesurfer/recon.py index a7791b49e8..15eb7b7930 100644 --- a/nipype/workflows/smri/freesurfer/recon.py +++ b/nipype/workflows/smri/freesurfer/recon.py @@ -146,6 +146,7 @@ def create_reconall_workflow(name="ReconAll", plugin_args=None, stop = 0.0001 exvivo = True entorhinal = True + rb_date = "2014-08-21" else: # 5.3 is default if 'v5.3' in fs_version_full: @@ -161,6 +162,7 @@ def create_reconall_workflow(name="ReconAll", plugin_args=None, stop = None exvivo = False entorhinal = False + rb_date = "2008-03-26" print("FreeSurfer Version: {0}".format(fs_version)) @@ -179,7 +181,8 @@ def setconfig(reg_template=None, color_table=None, lookup_table=None, wm_lookup_table=None, - awk_file=None): + awk_file=None, + rb_date=rb_date): """Set optional configurations to the default""" from nipype.workflows.smri.freesurfer.utils import getdefaultconfig def checkarg(arg, default): @@ -188,7 +191,7 @@ def checkarg(arg, default): return arg else: return default - defaultconfig = getdefaultconfig(exitonfail=True) + defaultconfig = getdefaultconfig(exitonfail=True, rb_date=rb_date) # set the default template and classifier files reg_template = checkarg(reg_template, defaultconfig['registration_template']) reg_template_withskull = checkarg(reg_template_withskull, diff --git a/nipype/workflows/smri/freesurfer/utils.py b/nipype/workflows/smri/freesurfer/utils.py index 7ce98a4642..69eb22911e 100644 --- a/nipype/workflows/smri/freesurfer/utils.py +++ b/nipype/workflows/smri/freesurfer/utils.py @@ -420,7 +420,7 @@ def mkdir_p(path): else: raise -def getdefaultconfig(exitonfail=False): +def getdefaultconfig(exitonfail=False, rb_date="2014-08-21"): config = { 'custom_atlas' : None, 'cw256' : False, 'field_strength' : '1.5T', @@ -440,9 +440,9 @@ def getdefaultconfig(exitonfail=False): config['awk_file'] = os.path.join(config['fs_home'], 'bin', 'extract_talairach_avi_QA.awk') config['registration_template'] = os.path.join(config['fs_home'], 'average', - 'RB_all_2014-08-21.gca') + 'RB_all_{0}.gca'.format(rb_date)) config['registration_template_withskull'] = os.path.join(config['fs_home'], 'average', - 'RB_all_withskull_2014-08-21.gca') + 'RB_all_withskull_{0}.gca'.format(rb_date)) for hemi in ('lh', 'rh'): config['{0}_atlas'.format(hemi)] = os.path.join( config['fs_home'], 'average', From c8ddf6dfc4f34364889fbd0c4bc6c7726a24da32 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Fri, 1 Apr 2016 10:26:37 -0500 Subject: [PATCH 17/72] FIX: Fixes input to config for rb_date --- nipype/workflows/smri/freesurfer/recon.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/recon.py b/nipype/workflows/smri/freesurfer/recon.py index 15eb7b7930..fb5b1d3d22 100644 --- a/nipype/workflows/smri/freesurfer/recon.py +++ b/nipype/workflows/smri/freesurfer/recon.py @@ -182,7 +182,7 @@ def setconfig(reg_template=None, lookup_table=None, wm_lookup_table=None, awk_file=None, - rb_date=rb_date): + rb_date=None): """Set optional configurations to the default""" from nipype.workflows.smri.freesurfer.utils import getdefaultconfig def checkarg(arg, default): @@ -232,12 +232,14 @@ def checkarg(arg, default): 'lookup_table', 'wm_lookup_table', 'awk_file'] - - config_node = pe.Node(niu.Function(params, + + config_node = pe.Node(niu.Function(params.append('rb_date'), params, setconfig), name="config") + config_node.inputs.rb_date = rb_date + for param in params: reconall.connect(inputspec, param, config_node, param) From e81d637243686c16685d2d38abca86fb9c053081 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Fri, 1 Apr 2016 12:36:59 -0500 Subject: [PATCH 18/72] FIX: config function. --- nipype/workflows/smri/freesurfer/recon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/workflows/smri/freesurfer/recon.py b/nipype/workflows/smri/freesurfer/recon.py index fb5b1d3d22..33db7bd44c 100644 --- a/nipype/workflows/smri/freesurfer/recon.py +++ b/nipype/workflows/smri/freesurfer/recon.py @@ -233,7 +233,7 @@ def checkarg(arg, default): 'wm_lookup_table', 'awk_file'] - config_node = pe.Node(niu.Function(params.append('rb_date'), + config_node = pe.Node(niu.Function(params + ['rb_date'], params, setconfig), name="config") From 97e1021c8a66ef5ced475ea1712b384de5194b55 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Fri, 1 Apr 2016 15:01:32 -0500 Subject: [PATCH 19/72] FIX: Switches around the intensity normalization for 5.3 --- .../workflows/smri/freesurfer/autorecon1.py | 51 +++++++--- .../workflows/smri/freesurfer/autorecon2.py | 95 +++++++++++-------- nipype/workflows/smri/freesurfer/ba_maps.py | 2 +- nipype/workflows/smri/freesurfer/recon.py | 7 +- 4 files changed, 101 insertions(+), 54 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon1.py b/nipype/workflows/smri/freesurfer/autorecon1.py index db26ea77d4..a258bc5dd4 100644 --- a/nipype/workflows/smri/freesurfer/autorecon1.py +++ b/nipype/workflows/smri/freesurfer/autorecon1.py @@ -36,7 +36,8 @@ def checkT1s(T1_files, cw256=False): return T1_files, cw256, resample_type, origvol_names def create_AutoRecon1(name="AutoRecon1", longitudinal=False, distance=200, - custom_atlas=None, plugin_args=None, shrink=2, stop=0.0001): + custom_atlas=None, plugin_args=None, shrink=2, stop=0.0001, + fsvernum=5.3): """Creates the AutoRecon1 workflow in nipype. Inputs:: @@ -239,14 +240,9 @@ def createTemplate(in_files, out_file): bias_correction.inputs.protocol_iterations = 1000 bias_correction.inputs.distance = distance if stop: - # per c.larsen, decrease convergence threshold (default is 0.001) bias_correction.inputs.stop = stop if shrink: - # per c.larsen, decrease shrink parameter: finer sampling (default is 4) bias_correction.inputs.shrink = shrink - # add the mask, as per c.larsen, bias-field correction is known to work - # much better when the brain area is properly masked, in this case by - # brainmask.mgz. bias_correction.inputs.no_rescale = True bias_correction.inputs.out_file = 'orig_nu.mgz' @@ -340,6 +336,28 @@ def awkfile(in_file, log_file): tal_qc = pe.Node(TalairachQC(), name="Detect_Aligment_Failures") ar1_wf.connect([(awk_logfile, tal_qc, [('log_file', 'log_file')])]) + + if fsvernum < 6: + # intensity correction is performed before normalization + intensity_correction = pe.Node( + MNIBiasCorrection(), name="Intensity_Correction") + intensity_correction.inputs.out_file = 'nu.mgz' + intensity_correction.inputs.iterations = 2 + ar2_wf.connect([(inputspec, intensity_correction, [('orig', 'in_file'), + ('brainmask', 'mask'), + ('transform', 'transform')])]) + + + add_to_header_nu = pe.Node(AddXFormToHeader(), name="Add_XForm_to_NU") + add_to_header_nu.inputs.copy_name = True + add_to_header_nu.inputs.out_file = 'nu.mgz' + ar2_wf.connect([(intensity_correction, add_to_header_nu, [('out_file', 'in_file'), + ]), + (copy_transform, add_to_header_nu, + [('out_file', 'transform')]) + ]) + + # Intensity Normalization # Performs intensity normalization of the orig volume and places the result in mri/T1.mgz. # Attempts to correct for fluctuations in intensity that would otherwise make intensity-based @@ -349,10 +367,13 @@ def awkfile(in_file, log_file): mri_normalize = pe.Node(Normalize(), name="Normalize_T1") mri_normalize.inputs.gradient = 1 mri_normalize.inputs.out_file = 'T1.mgz' - ar1_wf.connect([(add_xform_to_orig_nu, mri_normalize, [('out_file', 'in_file')]), - (copy_transform, mri_normalize, - [('out_file', 'transform')]), - ]) + + if fsvernum < 6: + ar1_wf.connect([(add_to_header_nu, mri_normalize, [('out_file', 'in_file')])]) + else: + ar1_wf.connect([(add_xform_to_orig_nu, mri_normalize, [('out_file', 'in_file')])]) + + ar1_wf.connect([(copy_transform, mri_normalize, [('out_file', 'transform')])]) # Skull Strip """ @@ -422,8 +443,14 @@ def awkfile(in_file, log_file): 'brainmask_auto', 'brainmask', 'braintemplate'] - outputspec = pe.Node(IdentityInterface(fields=outputs), - name="outputspec") + + if fsvernum < 6: + outputspec = pe.Node(IdentityInterface(fields=outputs + 'nu'), + name="outputspec") + ar1_wf.connect([(add_to_header_nu, outputspec, [('out_file', 'nu')])]) + else: + outputspec = pe.Node(IdentityInterface(fields=outputs), + name="outputspec") ar1_wf.connect([(T1_image_preparation, outputspec, [('out_file', 'origvols')]), (T2_convert, outputspec, [('out_file', 't2_raw')]), diff --git a/nipype/workflows/smri/freesurfer/autorecon2.py b/nipype/workflows/smri/freesurfer/autorecon2.py index 2fd85bce13..955dbb93f2 100644 --- a/nipype/workflows/smri/freesurfer/autorecon2.py +++ b/nipype/workflows/smri/freesurfer/autorecon2.py @@ -11,12 +11,13 @@ def copy_ltas(in_file, subjects_dir, subject_id, long_template): return out_file def create_AutoRecon2(name="AutoRecon2", longitudinal=False, - field_strength="1.5T", plugin_args=None): + plugin_args=None, fsvernum=5.3): # AutoRecon2 # Workflow ar2_wf = pe.Workflow(name=name) inputspec = pe.Node(IdentityInterface(fields=['orig', + 'nu', # version < 6 'brainmask', 'transform', 'subject_id', @@ -47,40 +48,39 @@ def create_AutoRecon2(name="AutoRecon2", longitudinal=False, inputspec.inputs.timepoints = config['timepoints'] - # NU Intensity Correction - """ - Non-parametric Non-uniform intensity Normalization (N3), corrects for - intensity non-uniformity in MR data, making relatively few assumptions about - the data. This runs the MINC tool 'nu_correct'. - """ - intensity_correction = pe.Node( - MNIBiasCorrection(), name="Intensity_Correction") - intensity_correction.inputs.iterations = 1 - intensity_correction.inputs.protocol_iterations = 1000 - intensity_correction.inputs.stop = 0.0001 - intensity_correction.inputs.shrink = 2 - if field_strength == '3T': - intensity_correction.inputs.distance = 50 - else: - # default for 1.5T scans - intensity_correction.inputs.distance = 200 - - intensity_correction.inputs.out_file = 'nu.mgz' - ar2_wf.connect([(inputspec, intensity_correction, [('orig', 'in_file'), - ('brainmask', 'mask'), - ('transform', 'transform') - ]) - ]) - - add_to_header_nu = pe.Node(AddXFormToHeader(), name="Add_XForm_to_NU") - add_to_header_nu.inputs.copy_name = True - add_to_header_nu.inputs.out_file = 'nu.mgz' - ar2_wf.connect([(intensity_correction, add_to_header_nu, [('out_file', 'in_file'), + if fsvernum >= 6: + # NU Intensity Correction + """ + Non-parametric Non-uniform intensity Normalization (N3), corrects for + intensity non-uniformity in MR data, making relatively few assumptions about + the data. This runs the MINC tool 'nu_correct'. + """ + intensity_correction = pe.Node( + MNIBiasCorrection(), name="Intensity_Correction") + intensity_correction.inputs.out_file = 'nu.mgz' + ar2_wf.connect([(inputspec, intensity_correction, [('orig', 'in_file'), + ('brainmask', 'mask'), + ('transform', 'transform')])]) + + # intensity correction parameters are more specific in 6+ + intensity_correction.inputs.iterations = 1 + intensity_correction.inputs.protocol_iterations = 1000 + if stop: + intensity_correction.inputs.stop = stop + if shrink: + intensity_correction.inputs.shrink = shrink + intensity_correction.inputs.distance = distance + + add_to_header_nu = pe.Node(AddXFormToHeader(), name="Add_XForm_to_NU") + add_to_header_nu.inputs.copy_name = True + add_to_header_nu.inputs.out_file = 'nu.mgz' + ar2_wf.connect([(intensity_correction, add_to_header_nu, [('out_file', 'in_file'), ]), - (inputspec, add_to_header_nu, - [('transform', 'transform')]) + (inputspec, add_to_header_nu, + [('transform', 'transform')]) ]) + # EM Registration """ Computes the transform to align the mri/nu.mgz volume to the default GCA @@ -103,8 +103,12 @@ def create_AutoRecon2(name="AutoRecon2", longitudinal=False, align_transform.plugin_args = plugin_args ar2_wf.connect([(inputspec, align_transform, [('brainmask', 'mask'), ('reg_template', 'template'), - ('num_threads', 'num_threads')]), - (add_to_header_nu, align_transform, [('out_file', 'in_file')])]) + ('num_threads', 'num_threads')])]) + if fsvernum >= 6: + ar2_wf.connect([(add_to_header_nu, align_transform, [('out_file', 'in_file')])]) + else: + ar2_wf.connect([(inputspec, align_transform, [('nu', 'in_file')])]) + # CA Normalize """ @@ -128,8 +132,12 @@ def create_AutoRecon2(name="AutoRecon2", longitudinal=False, ar2_wf.connect([(align_transform, ca_normalize, [('out_file', 'transform')]), (inputspec, ca_normalize, [('brainmask', 'mask'), - ('reg_template', 'atlas')]), - (add_to_header_nu, ca_normalize, [('out_file', 'in_file')])]) + ('reg_template', 'atlas')])]) + if fsvernum >= 6: + ar2_wf.connect([(add_to_header_nu, ca_normalize, [('out_file', 'in_file')])]) + else: + ar2_wf.connect([(inputspec, ca_normalize, [('nu', 'in_file')])]) + # CA Register # Computes a nonlinear transform to align with GCA atlas. @@ -159,8 +167,11 @@ def create_AutoRecon2(name="AutoRecon2", longitudinal=False, remove_neck.inputs.radius = 25 remove_neck.inputs.out_file = 'nu_noneck.mgz' ar2_wf.connect([(ca_register, remove_neck, [('out_file', 'transform')]), - (add_to_header_nu, remove_neck, [('out_file', 'in_file')]), (inputspec, remove_neck, [('reg_template', 'template')])]) + if fsvernum >= 6: + ar2_wf.connect([(add_to_header_nu, remove_neck, [('out_file', 'in_file')])]) + else: + ar2_wf.connect([(inputspec, remove_neck, [('nu', 'in_file')])]) # SkullLTA (EM Registration, with Skull) # Computes transform to align volume mri/nu_noneck.mgz with GCA volume @@ -680,8 +691,14 @@ def create_AutoRecon2(name="AutoRecon2", longitudinal=False, outputspec = pe.Node(IdentityInterface(fields=outputs), name="outputspec") - ar2_wf.connect([(add_to_header_nu, outputspec, [('out_file', 'nu')]), - (align_transform, outputspec, [('out_file', 'tal_lta')]), + if fsvernum >= 6: + ar2_wf.connect([(add_to_header_nu, outputspec, [('out_file', 'nu')])]) + else: + # add to outputspec to perserve datasinking + ar2_wf.connect([(inputspec, outputspec, [('nu', 'nu')])]) + + + ar2_wf.connect([(align_transform, outputspec, [('out_file', 'tal_lta')]), (ca_normalize, outputspec, [('out_file', 'norm')]), (ca_normalize, outputspec, [('control_points', 'ctrl_pts')]), (ca_register, outputspec, [('out_file', 'tal_m3z')]), diff --git a/nipype/workflows/smri/freesurfer/ba_maps.py b/nipype/workflows/smri/freesurfer/ba_maps.py index 6602fdeeb5..a8054e9669 100644 --- a/nipype/workflows/smri/freesurfer/ba_maps.py +++ b/nipype/workflows/smri/freesurfer/ba_maps.py @@ -67,7 +67,7 @@ def create_ba_maps_wf(name="Brodmann_Area_Maps", th3=True, exvivo=True, out_files = list() if threshold: for label in labels: - if label == 'perirhinal' and entorhinal: + if label == 'perirhinal' and not entorhinal: # versions < 6.0 do not use thresh.perirhinal continue if exvivo: diff --git a/nipype/workflows/smri/freesurfer/recon.py b/nipype/workflows/smri/freesurfer/recon.py index 33db7bd44c..e44091cdd9 100644 --- a/nipype/workflows/smri/freesurfer/recon.py +++ b/nipype/workflows/smri/freesurfer/recon.py @@ -139,6 +139,7 @@ def create_reconall_workflow(name="ReconAll", plugin_args=None, fs_version_full = Info.version() if 'v6.0' in fs_version_full or 'dev' in fs_version_full: # assuming that dev is 6.0 + fsvernum = 6.0 fs_version = 'v6.0' th3 = True shrink = 2 @@ -149,6 +150,7 @@ def create_reconall_workflow(name="ReconAll", plugin_args=None, rb_date = "2014-08-21" else: # 5.3 is default + fsvernum = 5.3 if 'v5.3' in fs_version_full: fs_version = 'v5.3' else: @@ -245,7 +247,8 @@ def checkarg(arg, default): # create AutoRecon1 ar1_wf, ar1_outputs = create_AutoRecon1(plugin_args=plugin_args, stop=stop, - distance=distance, shrink=shrink) + distance=distance, shrink=shrink, + fsvernum=fsvernum) # connect inputs for AutoRecon1 reconall.connect([(inputspec, ar1_wf, [('T1_files', 'inputspec.T1_files'), ('T2_file', 'inputspec.T2_file'), @@ -257,7 +260,7 @@ def checkarg(arg, default): ('awk_file', 'inputspec.awk_file')])]) # create AutoRecon2 - ar2_wf, ar2_outputs = create_AutoRecon2(plugin_args=plugin_args) + ar2_wf, ar2_outputs = create_AutoRecon2(plugin_args=plugin_args, fsvernum=fsvernum) # connect inputs for AutoRecon2 reconall.connect([(inputspec, ar2_wf, [('num_threads', 'inputspec.num_threads')]), (config_node, ar2_wf, [('reg_template_withskull', From c1f8aed231da7fdeba6770fb2404c4b94b660628 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Fri, 1 Apr 2016 15:06:39 -0500 Subject: [PATCH 20/72] FIX: fixes connections ar1 --- nipype/workflows/smri/freesurfer/autorecon1.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon1.py b/nipype/workflows/smri/freesurfer/autorecon1.py index a258bc5dd4..975382e761 100644 --- a/nipype/workflows/smri/freesurfer/autorecon1.py +++ b/nipype/workflows/smri/freesurfer/autorecon1.py @@ -343,15 +343,14 @@ def awkfile(in_file, log_file): MNIBiasCorrection(), name="Intensity_Correction") intensity_correction.inputs.out_file = 'nu.mgz' intensity_correction.inputs.iterations = 2 - ar2_wf.connect([(inputspec, intensity_correction, [('orig', 'in_file'), - ('brainmask', 'mask'), - ('transform', 'transform')])]) + ar1_wf.connect([(add_xform_to_orig, intensity_correction, [('out_file', 'in_file')]), + (copy_transform, intensity_correction, [('transform', 'transform')])]) add_to_header_nu = pe.Node(AddXFormToHeader(), name="Add_XForm_to_NU") add_to_header_nu.inputs.copy_name = True add_to_header_nu.inputs.out_file = 'nu.mgz' - ar2_wf.connect([(intensity_correction, add_to_header_nu, [('out_file', 'in_file'), + ar1_wf.connect([(intensity_correction, add_to_header_nu, [('out_file', 'in_file'), ]), (copy_transform, add_to_header_nu, [('out_file', 'transform')]) From 4d160087ad6b7930aa829f72aeda7e1ec6a2155c Mon Sep 17 00:00:00 2001 From: David Ellis Date: Fri, 1 Apr 2016 15:08:02 -0500 Subject: [PATCH 21/72] FIX: corrects the output for copy_transform --- nipype/workflows/smri/freesurfer/autorecon1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon1.py b/nipype/workflows/smri/freesurfer/autorecon1.py index 975382e761..1979a5c235 100644 --- a/nipype/workflows/smri/freesurfer/autorecon1.py +++ b/nipype/workflows/smri/freesurfer/autorecon1.py @@ -344,7 +344,7 @@ def awkfile(in_file, log_file): intensity_correction.inputs.out_file = 'nu.mgz' intensity_correction.inputs.iterations = 2 ar1_wf.connect([(add_xform_to_orig, intensity_correction, [('out_file', 'in_file')]), - (copy_transform, intensity_correction, [('transform', 'transform')])]) + (copy_transform, intensity_correction, [('out_file', 'transform')])]) add_to_header_nu = pe.Node(AddXFormToHeader(), name="Add_XForm_to_NU") From 3d60d7d51673e484c76d4052ad26609b9e5545bd Mon Sep 17 00:00:00 2001 From: David Ellis Date: Fri, 1 Apr 2016 15:09:19 -0500 Subject: [PATCH 22/72] FIX: adds item to outpus for autorecon1 --- nipype/workflows/smri/freesurfer/autorecon1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon1.py b/nipype/workflows/smri/freesurfer/autorecon1.py index 1979a5c235..d043115308 100644 --- a/nipype/workflows/smri/freesurfer/autorecon1.py +++ b/nipype/workflows/smri/freesurfer/autorecon1.py @@ -444,7 +444,7 @@ def awkfile(in_file, log_file): 'braintemplate'] if fsvernum < 6: - outputspec = pe.Node(IdentityInterface(fields=outputs + 'nu'), + outputspec = pe.Node(IdentityInterface(fields=outputs + ['nu']), name="outputspec") ar1_wf.connect([(add_to_header_nu, outputspec, [('out_file', 'nu')])]) else: From 06d5fbc0b64cd29e49bcea69b871f88d0966459c Mon Sep 17 00:00:00 2001 From: David Ellis Date: Mon, 4 Apr 2016 09:13:57 -0500 Subject: [PATCH 23/72] FIX: Connects 'nu' of autorecon1 to autorecon2. --- nipype/workflows/smri/freesurfer/recon.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nipype/workflows/smri/freesurfer/recon.py b/nipype/workflows/smri/freesurfer/recon.py index e44091cdd9..e76d4e618a 100644 --- a/nipype/workflows/smri/freesurfer/recon.py +++ b/nipype/workflows/smri/freesurfer/recon.py @@ -258,7 +258,6 @@ def checkarg(arg, default): (config_node, ar1_wf, [('reg_template_withskull', 'inputspec.reg_template_withskull'), ('awk_file', 'inputspec.awk_file')])]) - # create AutoRecon2 ar2_wf, ar2_outputs = create_AutoRecon2(plugin_args=plugin_args, fsvernum=fsvernum) # connect inputs for AutoRecon2 @@ -269,6 +268,10 @@ def checkarg(arg, default): (ar1_wf, ar2_wf, [('outputspec.brainmask', 'inputspec.brainmask'), ('outputspec.talairach', 'inputspec.transform'), ('outputspec.orig', 'inputspec.orig')])]) + + if fsvernum < 6: + reconall.connect([(ar1_wf, ar2_wf, [('outputspec.nu', 'inputspec.nu')])]) + # create AutoRecon3 ar3_wf, ar3_outputs = create_AutoRecon3(plugin_args=plugin_args, th3=th3, exvivo=exvivo, entorhinal=entorhinal) From 759f52e3cc71ffb4d0bc3bac3e44348ebeed9a56 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Mon, 4 Apr 2016 11:21:11 -0500 Subject: [PATCH 24/72] FIX: Takes out new inputs to CALabel. --- nipype/workflows/smri/freesurfer/autorecon2.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon2.py b/nipype/workflows/smri/freesurfer/autorecon2.py index 955dbb93f2..3f1a2d1443 100644 --- a/nipype/workflows/smri/freesurfer/autorecon2.py +++ b/nipype/workflows/smri/freesurfer/autorecon2.py @@ -218,8 +218,9 @@ def create_AutoRecon2(name="AutoRecon2", longitudinal=False, fuse_segmentations.inputs.out_file = 'aseg.fused.mgz' ca_label = pe.Node(CALabel(), name='CA_Label') - ca_label.inputs.relabel_unlikely = (9, .3) - ca_label.inputs.prior = 0.5 + if fsvernum > 6: + ca_label.inputs.relabel_unlikely = (9, .3) + ca_label.inputs.prior = 0.5 ca_label.inputs.align = True ca_label.inputs.out_file = 'aseg.auto_noCCseg.mgz' if plugin_args: From a6850cecaf8ca10897af91f0f840b022654ec1a4 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Tue, 5 Apr 2016 08:31:25 -0500 Subject: [PATCH 25/72] FIX: Removes in_aseg from ribbon masking. --- nipype/interfaces/freesurfer/utils.py | 3 ++- nipype/workflows/smri/freesurfer/autorecon3.py | 11 ++++++----- nipype/workflows/smri/freesurfer/recon.py | 3 ++- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/nipype/interfaces/freesurfer/utils.py b/nipype/interfaces/freesurfer/utils.py index 6edb1399e9..03f11e6d4b 100644 --- a/nipype/interfaces/freesurfer/utils.py +++ b/nipype/interfaces/freesurfer/utils.py @@ -2363,7 +2363,8 @@ def run(self, **inputs): copy2subjdir(self, self.inputs.rh_pial, 'surf', 'rh.pial') copy2subjdir(self, self.inputs.lh_white, 'surf', 'lh.white') copy2subjdir(self, self.inputs.rh_white, 'surf', 'rh.white') - copy2subjdir(self, self.inputs.in_aseg, 'mri') + if isdefined(self.inputs.in_aseg): + copy2subjdir(self, self.inputs.in_aseg, 'mri') return super(VolumeMask, self).run(**inputs) def _format_arg(self, name, spec, value): diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index d0dc354677..13f60aeb9e 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -8,7 +8,7 @@ from nipype.interfaces.io import DataGrabber def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, - th3=True, exvivo=True, entorhinal=True): + th3=True, exvivo=True, entorhinal=True, fsvernum=5.3): # AutoRecon3 # Workflow @@ -274,14 +274,15 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, volume_mask.inputs.copy_inputs = True - ar3_wf.connect([(inputspec, volume_mask, [('aseg_presurf', 'in_aseg'), - ('lh_white', 'lh_white'), - ('rh_white', 'rh_white'), - ]), + ar3_wf.connect([(inputspec, volume_mask, [('lh_white', 'lh_white'), + ('rh_white', 'rh_white')]), (ar3_lh_wf1, volume_mask, [('outputspec.pial', 'lh_pial')]), (ar3_rh_wf1, volume_mask, [('outputspec.pial', 'rh_pial')]), ]) + if fsvernum > 6: + ar3_wf.connect([(inputpsec, volume_mask, [('aseg_presurf', 'in_aseg')])]) + ar3_lh_wf2 = pe.Workflow(name="AutoRecon3_Left_2") ar3_rh_wf2 = pe.Workflow(name="AutoRecon3_Right_2") diff --git a/nipype/workflows/smri/freesurfer/recon.py b/nipype/workflows/smri/freesurfer/recon.py index e76d4e618a..f6996b6f2a 100644 --- a/nipype/workflows/smri/freesurfer/recon.py +++ b/nipype/workflows/smri/freesurfer/recon.py @@ -274,7 +274,8 @@ def checkarg(arg, default): # create AutoRecon3 ar3_wf, ar3_outputs = create_AutoRecon3(plugin_args=plugin_args, th3=th3, - exvivo=exvivo, entorhinal=entorhinal) + exvivo=exvivo, entorhinal=entorhinal, + fsvernum=fsvernum) # connect inputs for AutoRecon3 reconall.connect([(config_node, ar3_wf, [('lh_atlas', 'inputspec.lh_atlas'), ('rh_atlas', 'inputspec.rh_atlas'), From cd7dc15b266635ef63ff628a6be3e8c0c1a64ba9 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Tue, 5 Apr 2016 09:05:20 -0500 Subject: [PATCH 26/72] ENH: Allows for implicit aseg input in ribbon masking. --- nipype/interfaces/freesurfer/utils.py | 27 ++++++++++++++----- .../workflows/smri/freesurfer/autorecon3.py | 2 ++ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/nipype/interfaces/freesurfer/utils.py b/nipype/interfaces/freesurfer/utils.py index 03f11e6d4b..9ba8256fa6 100644 --- a/nipype/interfaces/freesurfer/utils.py +++ b/nipype/interfaces/freesurfer/utils.py @@ -35,21 +35,30 @@ def copy2subjdir(cls, in_file, folder=None, basename=None, subject_id=None): + """Method to copy an input to the subjects directory""" + # check that the input is defined + if not isdefined(in_file): + return in_file + # check that subjects_dir is defined if isdefined(cls.inputs.subjects_dir): subjects_dir = cls.inputs.subjects_dir else: - subjects_dir = os.getcwd() + subjects_dir = os.getcwd() #if not use cwd + # check for subject_id if not subject_id: if isdefined(cls.inputs.subject_id): subject_id = cls.inputs.subject_id else: - subject_id = 'subject_id' + subject_id = 'subject_id' #default + # check for basename if basename == None: basename = os.path.basename(in_file) + # check which folder to put the file in if folder != None: out_dir = os.path.join(subjects_dir, subject_id, folder) else: out_dir = os.path.join(subjects_dir, subject_id) + # make the output folder if it does not exist if not os.path.isdir(out_dir): os.makedirs(out_dir) out_file = os.path.join(out_dir, basename) @@ -58,7 +67,7 @@ def copy2subjdir(cls, in_file, folder=None, basename=None, subject_id=None): return out_file def createoutputdirs(outputs): - """create an output directories. If not created, some freesurfer interfaces fail""" + """create all output directories. If not created, some freesurfer interfaces fail""" for output in outputs.itervalues(): dirname = os.path.dirname(output) if not os.path.isdir(dirname): @@ -2301,11 +2310,16 @@ class VolumeMaskInputSpec(FSTraitedSpec): desc="Implicit input left white matter surface") rh_white = File(mandatory=True, exists=True, desc="Implicit input right white matter surface") + aseg = File(mandatory=True, exists=True, + xor=['in_aseg'], + desc="Implicit aseg.mgz segmentation. " + + "Specify a different aseg by using the 'in_aseg' input.") subject_id = traits.String('subject_id', usedefault=True, position=-1, argstr="%s", mandatory=True, desc="Subject being processed") # optional - in_aseg = File(argstr="--aseg_name %s", mandatory=False, exists=True, + in_aseg = File(argstr="--aseg_name %s", mandatory=False, + exists=True, xor=['aseg'], desc="Input aseg file for VolumeMask") save_ribbon = traits.Bool(argstr="--save_ribbon", mandatory=False, desc="option to save just the ribbon for the " + @@ -2363,8 +2377,9 @@ def run(self, **inputs): copy2subjdir(self, self.inputs.rh_pial, 'surf', 'rh.pial') copy2subjdir(self, self.inputs.lh_white, 'surf', 'lh.white') copy2subjdir(self, self.inputs.rh_white, 'surf', 'rh.white') - if isdefined(self.inputs.in_aseg): - copy2subjdir(self, self.inputs.in_aseg, 'mri') + copy2subjdir(self, self.inputs.in_aseg, 'mri') + copy2subjdir(self, self.inputs.aseg, 'mri', 'aseg.mgz') + return super(VolumeMask, self).run(**inputs) def _format_arg(self, name, spec, value): diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index 13f60aeb9e..6f31020273 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -282,6 +282,8 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, if fsvernum > 6: ar3_wf.connect([(inputpsec, volume_mask, [('aseg_presurf', 'in_aseg')])]) + else: + ar3_wf.connect([(inputpsec, volume_mask, [('aseg_presurf', 'aseg')])]) ar3_lh_wf2 = pe.Workflow(name="AutoRecon3_Left_2") ar3_rh_wf2 = pe.Workflow(name="AutoRecon3_Right_2") From c0cf40f488d423da8bd0799ef93b35536df85204 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Tue, 5 Apr 2016 09:07:17 -0500 Subject: [PATCH 27/72] FIX: Fixes typo. --- nipype/workflows/smri/freesurfer/autorecon3.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index 6f31020273..4b57b8790a 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -281,9 +281,9 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, ]) if fsvernum > 6: - ar3_wf.connect([(inputpsec, volume_mask, [('aseg_presurf', 'in_aseg')])]) + ar3_wf.connect([(inputspec, volume_mask, [('aseg_presurf', 'in_aseg')])]) else: - ar3_wf.connect([(inputpsec, volume_mask, [('aseg_presurf', 'aseg')])]) + ar3_wf.connect([(inputspec, volume_mask, [('aseg_presurf', 'aseg')])]) ar3_lh_wf2 = pe.Workflow(name="AutoRecon3_Left_2") ar3_rh_wf2 = pe.Workflow(name="AutoRecon3_Right_2") From 37fd56cab34da3e91f50abf7bdfb833d97bdd6b4 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Wed, 6 Apr 2016 12:41:56 -0500 Subject: [PATCH 28/72] FIX: Fixes source subject for BAMaps thresh. --- nipype/workflows/smri/freesurfer/ba_maps.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/ba_maps.py b/nipype/workflows/smri/freesurfer/ba_maps.py index a8054e9669..25f7c148c9 100644 --- a/nipype/workflows/smri/freesurfer/ba_maps.py +++ b/nipype/workflows/smri/freesurfer/ba_maps.py @@ -65,6 +65,7 @@ def create_ba_maps_wf(name="Brodmann_Area_Maps", th3=True, exvivo=True, white='surf/{0}.white'.format(hemisphere)) out_files = list() + source_fields = ['sphere_reg', 'white'] if threshold: for label in labels: if label == 'perirhinal' and not entorhinal: @@ -76,7 +77,8 @@ def create_ba_maps_wf(name="Brodmann_Area_Maps", th3=True, exvivo=True, out_file = '{0}.{1}.thresh.label'.format(hemisphere, label) out_files.append(out_file) field_template[label] = 'label/' + out_file - node_name = 'BA_Maps_' + hemisphere + '_Tresh' + source_fields.append(label) + node_name = 'BA_Maps_' + hemisphere + '_Thresh' else: for label in labels: if exvivo: @@ -86,9 +88,9 @@ def create_ba_maps_wf(name="Brodmann_Area_Maps", th3=True, exvivo=True, out_files.append(out_file) field_template[label] = 'label/' + out_file + source_fields.append(label) node_name = 'BA_Maps_' + hemisphere - source_fields = labels + ['sphere_reg', 'white'] source_subject = pe.Node(DataGrabber(outfields=source_fields), name=node_name + "_srcsubject") source_subject.inputs.template = '*' @@ -96,7 +98,7 @@ def create_ba_maps_wf(name="Brodmann_Area_Maps", th3=True, exvivo=True, source_subject.inputs.field_template = field_template ba_WF.connect([(inputspec, source_subject, [('src_subject_dir', 'base_directory')])]) - merge_labels = pe.Node(Merge(len(labels)), + merge_labels = pe.Node(Merge(len(out_files)), name=node_name + "_Merge") for i,label in enumerate(labels): ba_WF.connect([(source_subject, merge_labels, [(label, 'in{0}'.format(i+1))])]) From 1b95329ced63920f06aa068d40409c9d1456fecb Mon Sep 17 00:00:00 2001 From: David Ellis Date: Wed, 6 Apr 2016 12:54:46 -0500 Subject: [PATCH 29/72] FIX: Temporary fix for apas2aseg. Will still need to fix what is going wrong with aseg.mgz. --- nipype/workflows/smri/freesurfer/autorecon3.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index 4b57b8790a..19406678d5 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -6,6 +6,7 @@ from .ba_maps import create_ba_maps_wf from .utils import createsrcsubj from nipype.interfaces.io import DataGrabber +from .utils import copy_file def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, th3=True, exvivo=True, entorhinal=True, fsvernum=5.3): @@ -600,9 +601,17 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, (relabel_hypos, aparc_2_aseg_2009, [('out_file', 'aseg')]) ]) - apas_2_aseg = pe.Node(Apas2Aseg(), name="Apas_2_Aseg") + if fsvernum > 6: + apas_2_aseg = pe.Node(Apas2Aseg(), name="Apas_2_Aseg") + else: + apas_2_aseg = pe.Node(Function(['in_file', 'out_file'], + ['out_file'], + copy_file), + name="Copy2Aseg") + + ar3_wf.connect([(aparc_2_aseg, apas_2_aseg, [('out_file', 'in_file')])]) apas_2_aseg.inputs.out_file = "aseg.mgz" - ar3_wf.connect([(aparc_2_aseg, apas_2_aseg, [('out_file', 'in_file')])]) + # Segmentation Stats """ From 2daa8c19080735c329adfaa8f7d7d72f4d8482aa Mon Sep 17 00:00:00 2001 From: David Ellis Date: Wed, 6 Apr 2016 13:02:05 -0500 Subject: [PATCH 30/72] FIX: Changes reference of labels to source_fields. --- nipype/workflows/smri/freesurfer/ba_maps.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/workflows/smri/freesurfer/ba_maps.py b/nipype/workflows/smri/freesurfer/ba_maps.py index 25f7c148c9..21847226bd 100644 --- a/nipype/workflows/smri/freesurfer/ba_maps.py +++ b/nipype/workflows/smri/freesurfer/ba_maps.py @@ -100,7 +100,7 @@ def create_ba_maps_wf(name="Brodmann_Area_Maps", th3=True, exvivo=True, merge_labels = pe.Node(Merge(len(out_files)), name=node_name + "_Merge") - for i,label in enumerate(labels): + for i,label in enumerate(source_fields): ba_WF.connect([(source_subject, merge_labels, [(label, 'in{0}'.format(i+1))])]) node = pe.MapNode(Label2Label(), name=node_name, From 25b7e962b59742ba9571f48c406d20543427c7bb Mon Sep 17 00:00:00 2001 From: David Ellis Date: Wed, 6 Apr 2016 13:34:07 -0500 Subject: [PATCH 31/72] Fix: turns the mandatory flag off for aseg. --- nipype/interfaces/freesurfer/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/interfaces/freesurfer/utils.py b/nipype/interfaces/freesurfer/utils.py index 9ba8256fa6..2d1da1b78c 100644 --- a/nipype/interfaces/freesurfer/utils.py +++ b/nipype/interfaces/freesurfer/utils.py @@ -2310,7 +2310,7 @@ class VolumeMaskInputSpec(FSTraitedSpec): desc="Implicit input left white matter surface") rh_white = File(mandatory=True, exists=True, desc="Implicit input right white matter surface") - aseg = File(mandatory=True, exists=True, + aseg = File(exists=True, xor=['in_aseg'], desc="Implicit aseg.mgz segmentation. " + "Specify a different aseg by using the 'in_aseg' input.") From ac600650edfa34b2b992bdf27e34fdeff22a2ce5 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Wed, 6 Apr 2016 13:44:57 -0500 Subject: [PATCH 32/72] FIX: Fixes failure to copy rh.white --- nipype/interfaces/freesurfer/model.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/nipype/interfaces/freesurfer/model.py b/nipype/interfaces/freesurfer/model.py index 2980f147d8..7c9ba8bb68 100644 --- a/nipype/interfaces/freesurfer/model.py +++ b/nipype/interfaces/freesurfer/model.py @@ -859,7 +859,7 @@ def run(self, **inputs): copy2subjdir(self, self.inputs.lh_white, 'surf', 'lh.white') copy2subjdir(self, self.inputs.rh_white, - 'Surf', 'Rh.White') + 'surf', 'rh.white') copy2subjdir(self, self.inputs.lh_pial, 'surf', 'lh.pial') copy2subjdir(self, self.inputs.rh_pial, @@ -872,8 +872,7 @@ def run(self, **inputs): os.path.join('mri', 'transforms'), 'talairach.xfm') copy2subjdir(self, self.inputs.in_intensity, 'mri') - if isdefined(self.inputs.brainmask_file): - copy2subjdir(self, self.inputs.brainmask_file, 'mri') + copy2subjdir(self, self.inputs.brainmask_file, 'mri') return super(SegStatsReconAll, self).run(**inputs) From d6560f1b837ae600253638b24225f1e1f39cf090 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Wed, 6 Apr 2016 13:51:46 -0500 Subject: [PATCH 33/72] FIX: Adds filled input to Aparc2Aseg. --- nipype/interfaces/freesurfer/utils.py | 3 +++ nipype/workflows/smri/freesurfer/autorecon3.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/nipype/interfaces/freesurfer/utils.py b/nipype/interfaces/freesurfer/utils.py index 2d1da1b78c..016655c032 100644 --- a/nipype/interfaces/freesurfer/utils.py +++ b/nipype/interfaces/freesurfer/utils.py @@ -2742,6 +2742,8 @@ class Aparc2AsegInputSpec(FSTraitedSpec): rh_annotation = File(mandatory=True, exists=True, desc="Input file must be /label/rh.aparc.annot") # optional + filled = File(exists=True, + desc="Implicit input filled file. Only required with FS v5.3.") aseg = File(argstr="--aseg %s", mandatory=False, exists=True, desc="Input aseg file") volmask = traits.Bool(argstr="--volmask", mandatory=False, @@ -2824,6 +2826,7 @@ def run(self, **inputs): copy2subjdir(self, self.inputs.rh_ribbon, 'mri', 'rh.ribbon.mgz') copy2subjdir(self, self.inputs.ribbon, 'mri', 'ribbon.mgz') copy2subjdir(self, self.inputs.aseg, 'mri') + copy2subjdir(self, self.inputs.filled, 'mri', 'filled.mgz') copy2subjdir(self, self.inputs.lh_annotation, 'label') copy2subjdir(self, self.inputs.rh_annotation, 'label') diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index 19406678d5..b4b5162693 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -685,6 +685,9 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, (aparc_2_aseg, wm_parcellation, [('out_file', 'ctxseg')]) ]) + if fsvernum < 6: + ar3_wf.connect([(inputspec, wm_parcellation, [('filled', 'filled')])]) + # White Matter Segmentation Stats wm_segstats = pe.Node(SegStatsReconAll(), name="WM_Segmentation_Statistics") From 9057ffa64b8c434795285b4a4291a8f4a04e8798 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Wed, 6 Apr 2016 14:11:07 -0500 Subject: [PATCH 34/72] FIX: Allows for aseg to be copied in segstats for 5.3. --- nipype/interfaces/freesurfer/model.py | 4 ++++ nipype/workflows/smri/freesurfer/autorecon3.py | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/nipype/interfaces/freesurfer/model.py b/nipype/interfaces/freesurfer/model.py index 7c9ba8bb68..f09ca64b8f 100644 --- a/nipype/interfaces/freesurfer/model.py +++ b/nipype/interfaces/freesurfer/model.py @@ -796,6 +796,8 @@ class SegStatsReconAllInputSpec(SegStatsInputSpec): desc="Input file must be /surf/lh.pial") rh_pial = File(mandatory=True, exists=True, desc="Input file must be /surf/rh.pial") + aseg = File(exists=True, + desc="Mandatory implicit input in 5.3") copy_inputs = traits.Bool(desc="If running as a node, set this to True " + "otherwise, this will copy the implicit inputs " + "to the node directory.") @@ -868,6 +870,8 @@ def run(self, **inputs): 'mri', 'ribbon.mgz') copy2subjdir(self, self.inputs.presurf_seg, 'mri', 'aseg.presurf.mgz') + copy2subjdir(self, self.inputs.aseg, + 'mri', 'aseg.mgz') copy2subjdir(self, self.inputs.transform, os.path.join('mri', 'transforms'), 'talairach.xfm') diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index b4b5162693..ed97153995 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -638,7 +638,6 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, ar3_wf.connect([(apas_2_aseg, segstats, [('out_file', 'segmentation_file')]), (inputspec, segstats, [('lh_white', 'lh_white'), ('rh_white', 'rh_white'), - ('aseg_presurf', 'presurf_seg'), ('transform', 'transform'), ('norm', 'in_intensity'), ('norm', 'partial_volume_file'), @@ -654,6 +653,12 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, ]), ]) + if fsvernum > 6: + ar3_wf.connect(inputspec, 'aseg_presurf', segstats, 'presurf_seg') + else: + ar3_wf.connect(inputspec, 'aseg_presurf', segstats, 'aseg') + + # White Matter Parcellation # Adds WM Parcellation info into the aseg and computes stat. From 1ec5bf0cb11ab406bc2968673190722a28360e6f Mon Sep 17 00:00:00 2001 From: David Ellis Date: Wed, 6 Apr 2016 16:11:00 -0500 Subject: [PATCH 35/72] FIX: Changes presurf_seg to not being mandatory. --- nipype/interfaces/freesurfer/model.py | 2 +- nipype/workflows/smri/freesurfer/ba_maps.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nipype/interfaces/freesurfer/model.py b/nipype/interfaces/freesurfer/model.py index f09ca64b8f..5196292835 100644 --- a/nipype/interfaces/freesurfer/model.py +++ b/nipype/interfaces/freesurfer/model.py @@ -780,7 +780,7 @@ class SegStatsReconAllInputSpec(SegStatsInputSpec): # implicit ribbon = traits.File(mandatory=True, exists=True, desc="Input file mri/ribbon.mgz") - presurf_seg = File(mandatory=True, exists=True, + presurf_seg = File(exists=True, desc="Input segmentation volume") transform = File(mandatory=True, exists=True, desc="Input transform file") diff --git a/nipype/workflows/smri/freesurfer/ba_maps.py b/nipype/workflows/smri/freesurfer/ba_maps.py index 21847226bd..2d7a1ea41b 100644 --- a/nipype/workflows/smri/freesurfer/ba_maps.py +++ b/nipype/workflows/smri/freesurfer/ba_maps.py @@ -103,7 +103,7 @@ def create_ba_maps_wf(name="Brodmann_Area_Maps", th3=True, exvivo=True, for i,label in enumerate(source_fields): ba_WF.connect([(source_subject, merge_labels, [(label, 'in{0}'.format(i+1))])]) - node = pe.MapNode(Label2Label(), name=node_name, + node = pe.MapNode(Label2Label(), name=node_name + '_Label2Label', iterfield=['source_label', 'out_file']) node.inputs.hemisphere = hemisphere node.inputs.out_file = out_files From 0b6eb84be7d10c491cee9e3c6b01e3c8f97a45af Mon Sep 17 00:00:00 2001 From: David Ellis Date: Wed, 6 Apr 2016 16:12:45 -0500 Subject: [PATCH 36/72] FIX: Updates WM_Parcellation_Stats to take aseg as input. --- nipype/workflows/smri/freesurfer/autorecon3.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index ed97153995..7d1ad252a8 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -724,6 +724,13 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, ]), ]) + if fsvernum > 6: + ar3_wf.connect(inputspec, 'aseg_presurf', segstats, 'presurf_seg') + else: + ar3_wf.connect(inputspec, 'aseg_presurf', segstats, 'aseg') + + + # add brodman area maps to the workflow ba_WF, ba_outputs = create_ba_maps_wf(th3=th3, exvivo=exvivo, entorhinal=entorhinal) From 987427aec06725eaa5cf283a2bc82138c46b0f1d Mon Sep 17 00:00:00 2001 From: David Ellis Date: Wed, 6 Apr 2016 16:14:35 -0500 Subject: [PATCH 37/72] FIX: Fixes typo when connecting workflows. --- nipype/workflows/smri/freesurfer/autorecon3.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index 7d1ad252a8..0411a41907 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -725,9 +725,9 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, ]) if fsvernum > 6: - ar3_wf.connect(inputspec, 'aseg_presurf', segstats, 'presurf_seg') + ar3_wf.connect(inputspec, 'aseg_presurf', wm_segstats, 'presurf_seg') else: - ar3_wf.connect(inputspec, 'aseg_presurf', segstats, 'aseg') + ar3_wf.connect(inputspec, 'aseg_presurf', wm_segstats, 'aseg') From 2c1c045a630597b5db977b6e62b91e5bbfbc4dc9 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Wed, 6 Apr 2016 16:41:34 -0500 Subject: [PATCH 38/72] FIX: Fixes error causing sphere.reg to be passed as a label. --- nipype/workflows/smri/freesurfer/ba_maps.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/ba_maps.py b/nipype/workflows/smri/freesurfer/ba_maps.py index 2d7a1ea41b..34c978c102 100644 --- a/nipype/workflows/smri/freesurfer/ba_maps.py +++ b/nipype/workflows/smri/freesurfer/ba_maps.py @@ -65,7 +65,7 @@ def create_ba_maps_wf(name="Brodmann_Area_Maps", th3=True, exvivo=True, white='surf/{0}.white'.format(hemisphere)) out_files = list() - source_fields = ['sphere_reg', 'white'] + source_fields = list() if threshold: for label in labels: if label == 'perirhinal' and not entorhinal: @@ -91,7 +91,7 @@ def create_ba_maps_wf(name="Brodmann_Area_Maps", th3=True, exvivo=True, source_fields.append(label) node_name = 'BA_Maps_' + hemisphere - source_subject = pe.Node(DataGrabber(outfields=source_fields), + source_subject = pe.Node(DataGrabber(outfields=source_fields + ['sphere_reg', 'white']), name=node_name + "_srcsubject") source_subject.inputs.template = '*' source_subject.inputs.sort_filelist = False From ce8a0df2d164d46f496ff6d78450b9057a40b8d2 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Thu, 7 Apr 2016 10:15:15 -0500 Subject: [PATCH 39/72] FIX: Changes orig_nu.mgz to nu.mgz for the input to EM_register. --- nipype/workflows/smri/freesurfer/autorecon1.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon1.py b/nipype/workflows/smri/freesurfer/autorecon1.py index d043115308..d43121077f 100644 --- a/nipype/workflows/smri/freesurfer/autorecon1.py +++ b/nipype/workflows/smri/freesurfer/autorecon1.py @@ -386,8 +386,12 @@ def awkfile(in_file, log_file): if plugin_args: mri_em_register.plugin_args = plugin_args - ar1_wf.connect([(add_xform_to_orig_nu, mri_em_register, [('out_file', 'in_file')]), - (inputspec, mri_em_register, [('num_threads', 'num_threads'), + if fsvernum < 6: + ar1_wf.connect(add_to_header_nu, 'out_file', mri_em_register, 'in_file') + else: + ar1_wf.connect(add_xform_to_orig_nu, 'out_file', mri_em_register, 'in_file') + + ar1_wf.connect([(inputspec, mri_em_register, [('num_threads', 'num_threads'), ('reg_template_withskull', 'template')])]) brainmask = pe.Node(WatershedSkullStrip(), From 7959d40c4e57cd9525dd353a0a87353423af044c Mon Sep 17 00:00:00 2001 From: David Ellis Date: Mon, 11 Apr 2016 11:56:35 -0500 Subject: [PATCH 40/72] ENH: Makes mris_make_surfaces compatable with the 5.3 recon-all. --- nipype/interfaces/freesurfer/utils.py | 15 ++++++------ .../workflows/smri/freesurfer/autorecon2.py | 13 ++++++++-- .../workflows/smri/freesurfer/autorecon3.py | 24 ++++++++++++++----- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/nipype/interfaces/freesurfer/utils.py b/nipype/interfaces/freesurfer/utils.py index 016655c032..ca5a207e4e 100644 --- a/nipype/interfaces/freesurfer/utils.py +++ b/nipype/interfaces/freesurfer/utils.py @@ -1902,6 +1902,8 @@ class MakeSurfacesInputSpec(FSTraitedSpec): argstr="-max %.1f", desc="No documentation (used for longitudinal processing)") longitudinal = traits.Bool( argstr="-long", desc="No documentation (used for longitudinal processing)") + white = traits.String(argstr="-white %s", + desc="White surface name") copy_inputs = traits.Bool(mandatory=False, desc="If running as a node, set this to True." + "This will copy the input files to the node " + @@ -1958,13 +1960,11 @@ def run(self, **inputs): folder='mri', basename='filled.mgz') for originalfile in [self.inputs.in_aseg, self.inputs.in_T1]: - if isdefined(originalfile): - copy2subjdir(self, originalfile, folder='mri') + copy2subjdir(self, originalfile, folder='mri') for originalfile in [self.inputs.orig_white, self.inputs.orig_pial, self.inputs.in_orig]: - if isdefined(originalfile): - copy2subjdir(self, originalfile, folder='surf') + copy2subjdir(self, originalfile, folder='surf') if isdefined(self.inputs.in_label): copy2subjdir(self, self.inputs.in_label, 'label', '{0}.aparc.annot'.format(self.inputs.hemisphere)) @@ -1981,9 +1981,11 @@ def _format_arg(self, name, spec, value): basename = os.path.basename(value) # whent the -mgz flag is specified, it assumes the mgz extension if self.inputs.mgz: - prefix = basename.rstrip('.mgz') + prefix = value.rstrip('.mgz') else: prefix = basename + if prefix == 'aseg': + return # aseg is already the default return spec.argstr % prefix elif name in ['orig_white', 'orig_pial']: # these inputs do take full file paths or even basenames @@ -2038,7 +2040,7 @@ def _list_outputs(self): class CurvatureInputSpec(FSTraitedSpec): in_file = File(argstr="%s", position=-2, mandatory=True, exists=True, - desc="Input file for Curvature") + copyfile=True, desc="Input file for Curvature") # optional threshold = traits.Float( argstr="-thresh %.3f", mandatory=False, desc="Undocumented input threshold") @@ -2082,7 +2084,6 @@ def _format_arg(self, name, spec, value): if self.inputs.copy_input: if name == 'in_file': basename = os.path.basename(value) - shutil.copy(value, basename) return spec.argstr % basename return super(Curvature, self)._format_arg(name, spec, value) diff --git a/nipype/workflows/smri/freesurfer/autorecon2.py b/nipype/workflows/smri/freesurfer/autorecon2.py index 3f1a2d1443..273994d9d5 100644 --- a/nipype/workflows/smri/freesurfer/autorecon2.py +++ b/nipype/workflows/smri/freesurfer/autorecon2.py @@ -156,8 +156,14 @@ def create_AutoRecon2(name="AutoRecon2", longitudinal=False, else: ca_register.inputs.levels = 2 ca_register.inputs.A = 1 - ar2_wf.connect([(ar1_inputs, ca_register, [('template_talairach_m3z', 'l_files')])]) + ar2_wf.connect([(inputspec, ca_register, [('template_talairach_m3z', 'l_files')])]) + + if fsvernum < 6: + # 5.3 runs two ca_register steps + ca_register2 = pe.Node(CARegister(), name='CA_Register2') + ca_register2.inputs.invert_and_save = True + ar2_wf.connect(ca_register, 'out_file', ca_register2, '') # Remove Neck """ The neck region is removed from the NU-corrected volume mri/nu.mgz. Makes use @@ -248,7 +254,10 @@ def create_AutoRecon2(name="AutoRecon2", longitudinal=False, ['out_file'], copy_file), name='Copy_CCSegmentation') - copy_cc.inputs.out_file = 'aseg.presurf.mgz' + if fsvernum > 6: + copy_cc.inputs.out_file = 'aseg.presurf.mgz' + else: + copy_cc.inputs.out_file = 'aseg.mgz' ar2_wf.connect([(segment_cc, copy_cc, [('out_file', 'in_file')]) ]) diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index 0411a41907..b62c8a504f 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -166,11 +166,19 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, # Pial Surface ar3_pial = pe.Node(MakeSurfaces(), name="Make_Pial_Surface") - ar3_pial.inputs.no_white = True ar3_pial.inputs.mgz = True ar3_pial.inputs.hemisphere = hemisphere ar3_pial.inputs.copy_inputs = True + + if fsvernum < 6: + hemi_wf.connect(hemi_inputspec1, 'white', ar3_pial, 'in_white') + ar3_pial.inputs.white = 'NOWRITE' + else: + ar3_pial.inputs.no_white = True + hemi_wf.connect([(hemi_inputspec1, ar3_pial, [('white', 'orig_pial'), + ('white', 'orig_white')])]) + hemi_wf.connect([(hemi_inputspec1, ar3_pial, [('wm', 'in_wm'), ('orig', 'in_orig'), ('filled', 'in_filled'), @@ -603,13 +611,17 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, if fsvernum > 6: apas_2_aseg = pe.Node(Apas2Aseg(), name="Apas_2_Aseg") + ar3_wf.connect([(aparc_2_aseg, apas_2_aseg, [('out_file', 'in_file')])]) else: - apas_2_aseg = pe.Node(Function(['in_file', 'out_file'], + # aseg.mgz gets edited in place, so we'll copy and pass it to the + # outputspec once aparc_2_aseg has completed + def out_aseg(in_aparcaseg, in_aseg, out_file): + out_file = copy_file(in_aseg, out_file) + return out_file + apas_2_aseg = pe.Node(Function(['in_aparcaseg', 'in_aseg', 'out_file'], ['out_file'], - copy_file), - name="Copy2Aseg") - - ar3_wf.connect([(aparc_2_aseg, apas_2_aseg, [('out_file', 'in_file')])]) + out_aseg), + name="Aseg") apas_2_aseg.inputs.out_file = "aseg.mgz" From 2c9cb25abfa9a54db01e52e7f9f01f7d5bf792b9 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Mon, 11 Apr 2016 12:02:25 -0500 Subject: [PATCH 41/72] FIX: Removes unnecessary step in autorecon2. --- nipype/workflows/smri/freesurfer/autorecon2.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon2.py b/nipype/workflows/smri/freesurfer/autorecon2.py index 273994d9d5..c616114fab 100644 --- a/nipype/workflows/smri/freesurfer/autorecon2.py +++ b/nipype/workflows/smri/freesurfer/autorecon2.py @@ -158,12 +158,6 @@ def create_AutoRecon2(name="AutoRecon2", longitudinal=False, ca_register.inputs.A = 1 ar2_wf.connect([(inputspec, ca_register, [('template_talairach_m3z', 'l_files')])]) - - if fsvernum < 6: - # 5.3 runs two ca_register steps - ca_register2 = pe.Node(CARegister(), name='CA_Register2') - ca_register2.inputs.invert_and_save = True - ar2_wf.connect(ca_register, 'out_file', ca_register2, '') # Remove Neck """ The neck region is removed from the NU-corrected volume mri/nu.mgz. Makes use From 490446e6ff3b0dfd13335f2cad5914fad6eeab9e Mon Sep 17 00:00:00 2001 From: David Ellis Date: Mon, 11 Apr 2016 12:07:36 -0500 Subject: [PATCH 42/72] ENH: Adds in_white to Make Surfaces. --- nipype/interfaces/freesurfer/utils.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nipype/interfaces/freesurfer/utils.py b/nipype/interfaces/freesurfer/utils.py index ca5a207e4e..4dfd428945 100644 --- a/nipype/interfaces/freesurfer/utils.py +++ b/nipype/interfaces/freesurfer/utils.py @@ -1876,6 +1876,7 @@ class MakeSurfacesInputSpec(FSTraitedSpec): in_filled = File(exists=True, mandatory=True, desc="Implicit input file filled.mgz") # optional + in_white = File(exists=True, desc="Implicit input that is sometimes used") in_label = File(exists=True, mandatory=False, xor=['noaparc'], desc="Implicit input label/.aparc.annot") orig_white = File(argstr="-orig_white %s", exists=True, mandatory=False, @@ -1958,6 +1959,8 @@ def run(self, **inputs): folder='mri', basename='wm.mgz') copy2subjdir(self, self.inputs.in_filled, folder='mri', basename='filled.mgz') + copy2subjdir(self, self.inputs.in_white, + 'surf', '{0}.white'.format(self.inputs.hemisphere)) for originalfile in [self.inputs.in_aseg, self.inputs.in_T1]: copy2subjdir(self, originalfile, folder='mri') From e262e78dd2d2b47532cbd728e306af3d0b4445fd Mon Sep 17 00:00:00 2001 From: David Ellis Date: Mon, 11 Apr 2016 12:58:15 -0500 Subject: [PATCH 43/72] FIX: Switches the format of arguments for mris_make_surfaces to basename for input images. --- nipype/interfaces/freesurfer/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/interfaces/freesurfer/utils.py b/nipype/interfaces/freesurfer/utils.py index 4dfd428945..c5ee985c66 100644 --- a/nipype/interfaces/freesurfer/utils.py +++ b/nipype/interfaces/freesurfer/utils.py @@ -1984,7 +1984,7 @@ def _format_arg(self, name, spec, value): basename = os.path.basename(value) # whent the -mgz flag is specified, it assumes the mgz extension if self.inputs.mgz: - prefix = value.rstrip('.mgz') + prefix = basename.rstrip('.mgz') else: prefix = basename if prefix == 'aseg': From 5060fdc56bc6dbb84f6069fa70f2fc3ed5a029cc Mon Sep 17 00:00:00 2001 From: David Ellis Date: Mon, 11 Apr 2016 13:03:15 -0500 Subject: [PATCH 44/72] FIX: Adds inputs to the copying of aseg_presurf to aseg.mgz. --- nipype/workflows/smri/freesurfer/autorecon3.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index b62c8a504f..c9ed659546 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -622,6 +622,9 @@ def out_aseg(in_aparcaseg, in_aseg, out_file): ['out_file'], out_aseg), name="Aseg") + ar3_wf.connect([(aparc_2_aseg, apas_2_aseg, [('out_file', 'in_aparcaseg')]), + (inputspec, apas_2_aseg, [('aseg_presurf', 'in_aseg')])]) + apas_2_aseg.inputs.out_file = "aseg.mgz" From 6c63ded2f2c1a71ab21249b69c5d2488401e54a6 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Mon, 11 Apr 2016 13:10:34 -0500 Subject: [PATCH 45/72] FIX: Changes .rsplit to os.path.splittext. --- nipype/interfaces/freesurfer/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/interfaces/freesurfer/utils.py b/nipype/interfaces/freesurfer/utils.py index c5ee985c66..03e1ab1a3b 100644 --- a/nipype/interfaces/freesurfer/utils.py +++ b/nipype/interfaces/freesurfer/utils.py @@ -1984,7 +1984,7 @@ def _format_arg(self, name, spec, value): basename = os.path.basename(value) # whent the -mgz flag is specified, it assumes the mgz extension if self.inputs.mgz: - prefix = basename.rstrip('.mgz') + prefix = os.path.splitext(basename)[0] else: prefix = basename if prefix == 'aseg': From 848442bb40368b7e16a63c1023ad3d0bc2ec61fa Mon Sep 17 00:00:00 2001 From: David Ellis Date: Mon, 11 Apr 2016 13:58:22 -0500 Subject: [PATCH 46/72] FIX: Removes the unnecessary inputs to MakeSurfaces for 53. --- nipype/workflows/smri/freesurfer/autorecon3.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index c9ed659546..56d1890e8c 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -172,8 +172,8 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, if fsvernum < 6: - hemi_wf.connect(hemi_inputspec1, 'white', ar3_pial, 'in_white') ar3_pial.inputs.white = 'NOWRITE' + hemi_wf.connect(hemi_inputspec1, 'white', ar3_pial, 'in_white') else: ar3_pial.inputs.no_white = True hemi_wf.connect([(hemi_inputspec1, ar3_pial, [('white', 'orig_pial'), @@ -182,8 +182,6 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, hemi_wf.connect([(hemi_inputspec1, ar3_pial, [('wm', 'in_wm'), ('orig', 'in_orig'), ('filled', 'in_filled'), - ('white', 'orig_pial'), - ('white', 'orig_white'), ('brain_finalsurfs', 'in_T1'), ('aseg_presurf', 'in_aseg')]), (ar3_parcellation, ar3_pial, [('out_file', 'in_label')]) From 1857064952b5bac9f7ac7775838116ff78f70338 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Tue, 12 Apr 2016 10:05:15 -0500 Subject: [PATCH 47/72] FIX: Allows the interface wrapper to know it is making a pial surface for 5.3.0. --- nipype/interfaces/freesurfer/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nipype/interfaces/freesurfer/utils.py b/nipype/interfaces/freesurfer/utils.py index 03e1ab1a3b..8ef75478f1 100644 --- a/nipype/interfaces/freesurfer/utils.py +++ b/nipype/interfaces/freesurfer/utils.py @@ -2025,8 +2025,8 @@ def _list_outputs(self): dest_dir, str(self.inputs.hemisphere) + '.area') # Something determines when a pial surface and thickness file is generated # but documentation doesn't say what. - # The orig_pial flag is just a guess - if isdefined(self.inputs.orig_pial): + # The orig_pial input is just a guess + if isdefined(self.inputs.orig_pial) or self.inputs.white == 'NOWRITE': outputs["out_curv"] = outputs["out_curv"] + ".pial" outputs["out_area"] = outputs["out_area"] + ".pial" outputs["out_pial"] = os.path.join( From ede459f57531651964d4f24d72c6430bb30b3c99 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Tue, 12 Apr 2016 11:02:54 -0500 Subject: [PATCH 48/72] FIX: Adds import statement to output aseg function. --- nipype/workflows/smri/freesurfer/autorecon3.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index 56d1890e8c..016f5880fa 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -614,6 +614,7 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, # aseg.mgz gets edited in place, so we'll copy and pass it to the # outputspec once aparc_2_aseg has completed def out_aseg(in_aparcaseg, in_aseg, out_file): + from .utils import copy_file out_file = copy_file(in_aseg, out_file) return out_file apas_2_aseg = pe.Node(Function(['in_aparcaseg', 'in_aseg', 'out_file'], From a2672c835eb2afd14267256496c16f274fa7b516 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Tue, 12 Apr 2016 11:10:50 -0500 Subject: [PATCH 49/72] FIX: Fixes import statement. --- nipype/workflows/smri/freesurfer/autorecon3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index 016f5880fa..893836442d 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -614,7 +614,7 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, # aseg.mgz gets edited in place, so we'll copy and pass it to the # outputspec once aparc_2_aseg has completed def out_aseg(in_aparcaseg, in_aseg, out_file): - from .utils import copy_file + import copy_file out_file = copy_file(in_aseg, out_file) return out_file apas_2_aseg = pe.Node(Function(['in_aparcaseg', 'in_aseg', 'out_file'], From 775f1f9b6637e30c832b6ae80322be21ed5af6bd Mon Sep 17 00:00:00 2001 From: David Ellis Date: Tue, 12 Apr 2016 11:19:27 -0500 Subject: [PATCH 50/72] FIX: Adds shutil to import for out_aseg function. --- nipype/workflows/smri/freesurfer/autorecon3.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index 893836442d..02337e98d2 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -614,8 +614,9 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, # aseg.mgz gets edited in place, so we'll copy and pass it to the # outputspec once aparc_2_aseg has completed def out_aseg(in_aparcaseg, in_aseg, out_file): - import copy_file - out_file = copy_file(in_aseg, out_file) + import shutil + out_file = os.path.abspath(out_file) + shutil.copy(in_aseg, out_file) return out_file apas_2_aseg = pe.Node(Function(['in_aparcaseg', 'in_aseg', 'out_file'], ['out_file'], From 44f1e29dc54c6cf1ff4af588fe63700096e4ae92 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Tue, 12 Apr 2016 11:26:25 -0500 Subject: [PATCH 51/72] FIX: Imports os for out_aseg function. --- nipype/workflows/smri/freesurfer/autorecon3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index 02337e98d2..ad1cff1498 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -6,7 +6,6 @@ from .ba_maps import create_ba_maps_wf from .utils import createsrcsubj from nipype.interfaces.io import DataGrabber -from .utils import copy_file def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, th3=True, exvivo=True, entorhinal=True, fsvernum=5.3): @@ -615,6 +614,7 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, # outputspec once aparc_2_aseg has completed def out_aseg(in_aparcaseg, in_aseg, out_file): import shutil + import os out_file = os.path.abspath(out_file) shutil.copy(in_aseg, out_file) return out_file From 022352c9ad14c1104d775bba0478d3c2cbba4126 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Tue, 12 Apr 2016 15:57:19 -0500 Subject: [PATCH 52/72] FIX: fixes bugs in recoding table workflow. --- nipype/workflows/smri/freesurfer/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/workflows/smri/freesurfer/utils.py b/nipype/workflows/smri/freesurfer/utils.py index 69eb22911e..b2d9d721ce 100644 --- a/nipype/workflows/smri/freesurfer/utils.py +++ b/nipype/workflows/smri/freesurfer/utils.py @@ -568,7 +568,7 @@ def minimizeSizeOfImage(outlabels): def create_recoding_wf(in_file, out_file=None): - wf = nipype.Workflow(name="RecodeLabels") + wf = pe.Workflow(name="RecodeLabels") inputspec = nipype.pipeline.Node(nipype.IdentityInterface(['labelmap', 'recode_file']), From f3acecc1b4443296c27eb17ef4de58d716fbeab8 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Tue, 12 Apr 2016 16:00:46 -0500 Subject: [PATCH 53/72] FIX: Changes nipype.pipeline.Node to pe.Node --- nipype/workflows/smri/freesurfer/utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/utils.py b/nipype/workflows/smri/freesurfer/utils.py index b2d9d721ce..94988865bf 100644 --- a/nipype/workflows/smri/freesurfer/utils.py +++ b/nipype/workflows/smri/freesurfer/utils.py @@ -570,12 +570,12 @@ def minimizeSizeOfImage(outlabels): def create_recoding_wf(in_file, out_file=None): wf = pe.Workflow(name="RecodeLabels") - inputspec = nipype.pipeline.Node(nipype.IdentityInterface(['labelmap', - 'recode_file']), - name="inputspec") + inputspec = pe.Node(niu.IdentityInterface(['labelmap', + 'recode_file']), + name="inputspec") inputspec.inputs.recode_file = in_file - convert_labelmap = nipype.pipeline.Node(fs.MRIConvert(), name="ConvertLabelMap") + convert_labelmap = pe.Node(fs.MRIConvert(), name="ConvertLabelMap") convert_labelmap.inputs.in_type = 'mgz' convert_labelmap.inputs.out_type = 'nii' convert_labelmap.inputs.out_orientation = 'RAS' From 7050d576a220dd907d01af5b9a81e97806143335 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Tue, 12 Apr 2016 16:06:15 -0500 Subject: [PATCH 54/72] FIX: Changes nipype.Node to pe.Node. --- nipype/workflows/smri/freesurfer/utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/utils.py b/nipype/workflows/smri/freesurfer/utils.py index 94988865bf..4f2f81f62a 100644 --- a/nipype/workflows/smri/freesurfer/utils.py +++ b/nipype/workflows/smri/freesurfer/utils.py @@ -582,7 +582,7 @@ def create_recoding_wf(in_file, out_file=None): convert_labelmap.inputs.out_file = 'labelmap.nii' wf.connect([(inputspec, convert_labelmap, [('labelmap', 'in_file')])]) - recode = nipype.Node(nipype.Function(['in_file', + recode = pe.Node(nipype.Function(['in_file', 'out_file', 'recode_file'], ['out_file'], @@ -596,13 +596,13 @@ def create_recoding_wf(in_file, out_file=None): wf.connect([(convert_labelmap, recode, [('out_file', 'in_file')]), (inputspec, recode, [('recode_file', 'recode_file')])]) - center_labelmap = nipype.Node(nipype.Function(['in_file'], ['out_file'], + center_labelmap = pe.Node(nipype.Function(['in_file'], ['out_file'], center_volume), name="CenterLabelMap") wf.connect([(recode, center_labelmap, [('out_file', 'in_file')])]) - outputspec = nipype.Node(nipype.IdentityInterface(['recodedlabelmap']), name="outputspec") + outputspec = pe.Node(nipype.IdentityInterface(['recodedlabelmap']), name="outputspec") wf.connect([(center_labelmap, outputspec, [('out_file', 'recodedlabelmap')])]) return wf From ccb4b164c71417334644be173eec60b3b25bb45d Mon Sep 17 00:00:00 2001 From: David Ellis Date: Tue, 12 Apr 2016 16:12:55 -0500 Subject: [PATCH 55/72] FIX: Changes nipype.Function to Function. --- nipype/workflows/smri/freesurfer/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/utils.py b/nipype/workflows/smri/freesurfer/utils.py index 4f2f81f62a..c9a530eb4b 100644 --- a/nipype/workflows/smri/freesurfer/utils.py +++ b/nipype/workflows/smri/freesurfer/utils.py @@ -582,7 +582,7 @@ def create_recoding_wf(in_file, out_file=None): convert_labelmap.inputs.out_file = 'labelmap.nii' wf.connect([(inputspec, convert_labelmap, [('labelmap', 'in_file')])]) - recode = pe.Node(nipype.Function(['in_file', + recode = pe.Node(Function(['in_file', 'out_file', 'recode_file'], ['out_file'], @@ -596,7 +596,7 @@ def create_recoding_wf(in_file, out_file=None): wf.connect([(convert_labelmap, recode, [('out_file', 'in_file')]), (inputspec, recode, [('recode_file', 'recode_file')])]) - center_labelmap = pe.Node(nipype.Function(['in_file'], ['out_file'], + center_labelmap = pe.Node(Function(['in_file'], ['out_file'], center_volume), name="CenterLabelMap") From 6c9886f3d4868138ddac39c9f5130157c479d5ba Mon Sep 17 00:00:00 2001 From: David Ellis Date: Tue, 12 Apr 2016 16:14:35 -0500 Subject: [PATCH 56/72] FIX: Replaces nipype.IdentityInterface with niu.IdentityInterface. --- nipype/workflows/smri/freesurfer/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/workflows/smri/freesurfer/utils.py b/nipype/workflows/smri/freesurfer/utils.py index c9a530eb4b..9e88bbf389 100644 --- a/nipype/workflows/smri/freesurfer/utils.py +++ b/nipype/workflows/smri/freesurfer/utils.py @@ -602,7 +602,7 @@ def create_recoding_wf(in_file, out_file=None): wf.connect([(recode, center_labelmap, [('out_file', 'in_file')])]) - outputspec = pe.Node(nipype.IdentityInterface(['recodedlabelmap']), name="outputspec") + outputspec = pe.Node(niu.IdentityInterface(['recodedlabelmap']), name="outputspec") wf.connect([(center_labelmap, outputspec, [('out_file', 'recodedlabelmap')])]) return wf From 01b84a9914768b3e9b96443bd743640f893b05b5 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Wed, 13 Apr 2016 10:41:33 -0500 Subject: [PATCH 57/72] ENH: Removes the relabels hypointensities for 5.3. --- nipype/interfaces/freesurfer/utils.py | 7 +++- .../workflows/smri/freesurfer/autorecon3.py | 41 +++++++++---------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/nipype/interfaces/freesurfer/utils.py b/nipype/interfaces/freesurfer/utils.py index 8ef75478f1..d8a9379bd2 100644 --- a/nipype/interfaces/freesurfer/utils.py +++ b/nipype/interfaces/freesurfer/utils.py @@ -2839,7 +2839,12 @@ def run(self, **inputs): def _format_arg(self, name, spec, value): if name == 'aseg': # aseg does not take a full filename - return spec.argstr % os.path.basename(value).replace('.mgz', '') + basename = os.path.basename(value).replace('.mgz', '') + if basename != 'aseg': + return spec.argstr % basename + else: + # aseg.mgz is the default + return elif name == 'out_file': return spec.argstr % os.path.abspath(value) diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index ad1cff1498..359f311f2b 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -550,14 +550,6 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, #End hemisphere2 workflow - # Relabel Hypointensities - relabel_hypos = pe.Node(RelabelHypointensities(), name="Relabel_Hypointensities") - relabel_hypos.inputs.out_file = 'aseg.presurf.hypos.mgz' - ar3_wf.connect([(inputspec, relabel_hypos, [('aseg_presurf', 'aseg'), - ('lh_white', 'lh_white'), - ('rh_white', 'rh_white'), - ])]) - # APARC to ASEG # Adds information from the ribbon into the aseg.mgz (volume parcellation). aparc_2_aseg = pe.Node(Aparc2Aseg(), name="Aparc2Aseg") @@ -578,9 +570,17 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, (volume_mask, aparc_2_aseg, [('rh_ribbon', 'rh_ribbon'), ('lh_ribbon', 'lh_ribbon'), ('out_ribbon', 'ribbon'), - ]), - (relabel_hypos, aparc_2_aseg, [('out_file', 'aseg')]) - ]) + ])]) + if fsvernum < 6: + ar3_wf.connect([(inputspec, aparc_2_aseg, [('aseg_presurf', 'aseg')])]) + else: + # Relabel Hypointensities + relabel_hypos = pe.Node(RelabelHypointensities(), name="Relabel_Hypointensities") + relabel_hypos.inputs.out_file = 'aseg.presurf.hypos.mgz' + ar3_wf.connect([(inputspec, relabel_hypos, [('aseg_presurf', 'aseg'), + ('lh_white', 'lh_white'), + ('rh_white', 'rh_white')])]) + ar3_wf.connect([(relabel_hypos, aparc_2_aseg, [('out_file', 'aseg')])]) aparc_2_aseg_2009 = pe.Node(Aparc2Aseg(), name="Aparc2Aseg_2009") aparc_2_aseg_2009.inputs.volmask = True @@ -601,14 +601,12 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, (volume_mask, aparc_2_aseg_2009, [('rh_ribbon', 'rh_ribbon'), ('lh_ribbon', 'lh_ribbon'), - ('out_ribbon', 'ribbon'), - ]), - (relabel_hypos, aparc_2_aseg_2009, [('out_file', 'aseg')]) - ]) + ('out_ribbon', 'ribbon')])]) if fsvernum > 6: apas_2_aseg = pe.Node(Apas2Aseg(), name="Apas_2_Aseg") - ar3_wf.connect([(aparc_2_aseg, apas_2_aseg, [('out_file', 'in_file')])]) + ar3_wf.connect([(aparc_2_aseg, apas_2_aseg, [('out_file', 'in_file')]), + (relabel_hypos, aparc_2_aseg_2009, [('out_file', 'aseg')])]) else: # aseg.mgz gets edited in place, so we'll copy and pass it to the # outputspec once aparc_2_aseg has completed @@ -702,8 +700,7 @@ def out_aseg(in_aparcaseg, in_aseg, out_file): ('out_ribbon', 'ribbon'), ]), (apas_2_aseg, wm_parcellation, [('out_file', 'aseg')]), - (aparc_2_aseg, wm_parcellation, [('out_file', 'ctxseg')]) - ]) + (aparc_2_aseg, wm_parcellation, [('out_file', 'ctxseg')])]) if fsvernum < 6: ar3_wf.connect([(inputspec, wm_parcellation, [('filled', 'filled')])]) @@ -745,7 +742,6 @@ def out_aseg(in_aparcaseg, in_aseg, out_file): ar3_wf.connect(inputspec, 'aseg_presurf', wm_segstats, 'aseg') - # add brodman area maps to the workflow ba_WF, ba_outputs = create_ba_maps_wf(th3=th3, exvivo=exvivo, entorhinal=entorhinal) @@ -937,11 +933,12 @@ def out_aseg(in_aparcaseg, in_aseg, out_file): (segstats, outputspec, [('summary_file', 'aseg_stats')]), (aparc_2_aseg_2009, outputspec, [('out_file', 'aparc_a2009s_aseg')]), (aparc_2_aseg, outputspec, [('out_file', 'aparc_aseg')]), - (relabel_hypos, outputspec, [('out_file', 'aseg_presurf_hypos')]), (volume_mask, outputspec, [('out_ribbon', 'ribbon'), ('lh_ribbon', 'lh_ribbon'), - ('rh_ribbon', 'rh_ribbon')]), - ]) + ('rh_ribbon', 'rh_ribbon')])]) + if fsvernum < 6: + ar3_wf.connect([(relabel_hypos, outputspec, [('out_file', 'aseg_presurf_hypos')])]) + for i, outputs in enumerate([hemi_outputs1, hemi_outputs2]): if i == 0: From 89e208c91c618894251fc86494372f305b1969fe Mon Sep 17 00:00:00 2001 From: David Ellis Date: Wed, 13 Apr 2016 10:45:43 -0500 Subject: [PATCH 58/72] FIX: Switches the presurf labelmap name back to aseg.presurf.mgz. --- nipype/workflows/smri/freesurfer/autorecon2.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon2.py b/nipype/workflows/smri/freesurfer/autorecon2.py index c616114fab..70459edf53 100644 --- a/nipype/workflows/smri/freesurfer/autorecon2.py +++ b/nipype/workflows/smri/freesurfer/autorecon2.py @@ -248,10 +248,7 @@ def create_AutoRecon2(name="AutoRecon2", longitudinal=False, ['out_file'], copy_file), name='Copy_CCSegmentation') - if fsvernum > 6: - copy_cc.inputs.out_file = 'aseg.presurf.mgz' - else: - copy_cc.inputs.out_file = 'aseg.mgz' + copy_cc.inputs.out_file = 'aseg.presurf.mgz' ar2_wf.connect([(segment_cc, copy_cc, [('out_file', 'in_file')]) ]) From aaf3b050b60f420fef6f7fca28671db68b3a44b7 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Wed, 13 Apr 2016 10:58:48 -0500 Subject: [PATCH 59/72] FIX: make check-before-commit --- .../interfaces/freesurfer/tests/test_auto_Aparc2Aseg.py | 1 + nipype/interfaces/freesurfer/tests/test_auto_Curvature.py | 1 + .../interfaces/freesurfer/tests/test_auto_MakeSurfaces.py | 3 +++ .../freesurfer/tests/test_auto_SegStatsReconAll.py | 4 ++-- .../interfaces/freesurfer/tests/test_auto_VolumeMask.py | 3 +++ nipype/interfaces/freesurfer/utils.py | 8 ++++---- nipype/workflows/smri/freesurfer/autorecon1.py | 8 ++++---- nipype/workflows/smri/freesurfer/autorecon2.py | 8 ++++---- nipype/workflows/smri/freesurfer/autorecon3.py | 4 ++-- nipype/workflows/smri/freesurfer/ba_maps.py | 2 +- nipype/workflows/smri/freesurfer/recon.py | 6 +++--- 11 files changed, 28 insertions(+), 20 deletions(-) diff --git a/nipype/interfaces/freesurfer/tests/test_auto_Aparc2Aseg.py b/nipype/interfaces/freesurfer/tests/test_auto_Aparc2Aseg.py index 27ea0eb162..8925054f05 100644 --- a/nipype/interfaces/freesurfer/tests/test_auto_Aparc2Aseg.py +++ b/nipype/interfaces/freesurfer/tests/test_auto_Aparc2Aseg.py @@ -19,6 +19,7 @@ def test_Aparc2Aseg_inputs(): environ=dict(nohash=True, usedefault=True, ), + filled=dict(), hypo_wm=dict(argstr='--hypo-as-wm', mandatory=False, ), diff --git a/nipype/interfaces/freesurfer/tests/test_auto_Curvature.py b/nipype/interfaces/freesurfer/tests/test_auto_Curvature.py index 5be32abc21..851c2acff9 100644 --- a/nipype/interfaces/freesurfer/tests/test_auto_Curvature.py +++ b/nipype/interfaces/freesurfer/tests/test_auto_Curvature.py @@ -19,6 +19,7 @@ def test_Curvature_inputs(): usedefault=True, ), in_file=dict(argstr='%s', + copyfile=True, mandatory=True, position=-2, ), diff --git a/nipype/interfaces/freesurfer/tests/test_auto_MakeSurfaces.py b/nipype/interfaces/freesurfer/tests/test_auto_MakeSurfaces.py index f2ca8c2a64..a34894fe99 100644 --- a/nipype/interfaces/freesurfer/tests/test_auto_MakeSurfaces.py +++ b/nipype/interfaces/freesurfer/tests/test_auto_MakeSurfaces.py @@ -35,6 +35,7 @@ def test_MakeSurfaces_inputs(): in_orig=dict(argstr='-orig %s', mandatory=True, ), + in_white=dict(), in_wm=dict(mandatory=True, ), longitudinal=dict(argstr='-long', @@ -66,6 +67,8 @@ def test_MakeSurfaces_inputs(): subjects_dir=dict(), terminal_output=dict(nohash=True, ), + white=dict(argstr='-white %s', + ), white_only=dict(argstr='-whiteonly', mandatory=False, ), diff --git a/nipype/interfaces/freesurfer/tests/test_auto_SegStatsReconAll.py b/nipype/interfaces/freesurfer/tests/test_auto_SegStatsReconAll.py index e15967ffec..4c0f8dcde6 100644 --- a/nipype/interfaces/freesurfer/tests/test_auto_SegStatsReconAll.py +++ b/nipype/interfaces/freesurfer/tests/test_auto_SegStatsReconAll.py @@ -10,6 +10,7 @@ def test_SegStatsReconAll_inputs(): ), args=dict(argstr='%s', ), + aseg=dict(), avgwf_file=dict(argstr='--avgwfvol %s', ), avgwf_txt_file=dict(argstr='--avgwf %s', @@ -85,8 +86,7 @@ def test_SegStatsReconAll_inputs(): ), partial_volume_file=dict(argstr='--pv %s', ), - presurf_seg=dict(mandatory=True, - ), + presurf_seg=dict(), rh_orig_nofix=dict(mandatory=True, ), rh_pial=dict(mandatory=True, diff --git a/nipype/interfaces/freesurfer/tests/test_auto_VolumeMask.py b/nipype/interfaces/freesurfer/tests/test_auto_VolumeMask.py index 81786550f5..c87f8716b5 100644 --- a/nipype/interfaces/freesurfer/tests/test_auto_VolumeMask.py +++ b/nipype/interfaces/freesurfer/tests/test_auto_VolumeMask.py @@ -6,6 +6,8 @@ def test_VolumeMask_inputs(): input_map = dict(args=dict(argstr='%s', ), + aseg=dict(xor=['in_aseg'], + ), copy_inputs=dict(mandatory=False, ), environ=dict(nohash=True, @@ -16,6 +18,7 @@ def test_VolumeMask_inputs(): ), in_aseg=dict(argstr='--aseg_name %s', mandatory=False, + xor=['aseg'], ), left_ribbonlabel=dict(argstr='--label_left_ribbon %d', mandatory=True, diff --git a/nipype/interfaces/freesurfer/utils.py b/nipype/interfaces/freesurfer/utils.py index d8a9379bd2..975dda9975 100644 --- a/nipype/interfaces/freesurfer/utils.py +++ b/nipype/interfaces/freesurfer/utils.py @@ -2315,14 +2315,14 @@ class VolumeMaskInputSpec(FSTraitedSpec): rh_white = File(mandatory=True, exists=True, desc="Implicit input right white matter surface") aseg = File(exists=True, - xor=['in_aseg'], - desc="Implicit aseg.mgz segmentation. " + + xor=['in_aseg'], + desc="Implicit aseg.mgz segmentation. " + "Specify a different aseg by using the 'in_aseg' input.") subject_id = traits.String('subject_id', usedefault=True, position=-1, argstr="%s", mandatory=True, desc="Subject being processed") # optional - in_aseg = File(argstr="--aseg_name %s", mandatory=False, + in_aseg = File(argstr="--aseg_name %s", mandatory=False, exists=True, xor=['aseg'], desc="Input aseg file for VolumeMask") save_ribbon = traits.Bool(argstr="--save_ribbon", mandatory=False, @@ -2383,7 +2383,7 @@ def run(self, **inputs): copy2subjdir(self, self.inputs.rh_white, 'surf', 'rh.white') copy2subjdir(self, self.inputs.in_aseg, 'mri') copy2subjdir(self, self.inputs.aseg, 'mri', 'aseg.mgz') - + return super(VolumeMask, self).run(**inputs) def _format_arg(self, name, spec, value): diff --git a/nipype/workflows/smri/freesurfer/autorecon1.py b/nipype/workflows/smri/freesurfer/autorecon1.py index d43121077f..161a690a9f 100644 --- a/nipype/workflows/smri/freesurfer/autorecon1.py +++ b/nipype/workflows/smri/freesurfer/autorecon1.py @@ -345,7 +345,7 @@ def awkfile(in_file, log_file): intensity_correction.inputs.iterations = 2 ar1_wf.connect([(add_xform_to_orig, intensity_correction, [('out_file', 'in_file')]), (copy_transform, intensity_correction, [('out_file', 'transform')])]) - + add_to_header_nu = pe.Node(AddXFormToHeader(), name="Add_XForm_to_NU") add_to_header_nu.inputs.copy_name = True @@ -356,7 +356,7 @@ def awkfile(in_file, log_file): [('out_file', 'transform')]) ]) - + # Intensity Normalization # Performs intensity normalization of the orig volume and places the result in mri/T1.mgz. # Attempts to correct for fluctuations in intensity that would otherwise make intensity-based @@ -368,7 +368,7 @@ def awkfile(in_file, log_file): mri_normalize.inputs.out_file = 'T1.mgz' if fsvernum < 6: - ar1_wf.connect([(add_to_header_nu, mri_normalize, [('out_file', 'in_file')])]) + ar1_wf.connect([(add_to_header_nu, mri_normalize, [('out_file', 'in_file')])]) else: ar1_wf.connect([(add_xform_to_orig_nu, mri_normalize, [('out_file', 'in_file')])]) @@ -390,7 +390,7 @@ def awkfile(in_file, log_file): ar1_wf.connect(add_to_header_nu, 'out_file', mri_em_register, 'in_file') else: ar1_wf.connect(add_xform_to_orig_nu, 'out_file', mri_em_register, 'in_file') - + ar1_wf.connect([(inputspec, mri_em_register, [('num_threads', 'num_threads'), ('reg_template_withskull', 'template')])]) diff --git a/nipype/workflows/smri/freesurfer/autorecon2.py b/nipype/workflows/smri/freesurfer/autorecon2.py index 70459edf53..3deabe6797 100644 --- a/nipype/workflows/smri/freesurfer/autorecon2.py +++ b/nipype/workflows/smri/freesurfer/autorecon2.py @@ -61,7 +61,7 @@ def create_AutoRecon2(name="AutoRecon2", longitudinal=False, ar2_wf.connect([(inputspec, intensity_correction, [('orig', 'in_file'), ('brainmask', 'mask'), ('transform', 'transform')])]) - + # intensity correction parameters are more specific in 6+ intensity_correction.inputs.iterations = 1 intensity_correction.inputs.protocol_iterations = 1000 @@ -70,7 +70,7 @@ def create_AutoRecon2(name="AutoRecon2", longitudinal=False, if shrink: intensity_correction.inputs.shrink = shrink intensity_correction.inputs.distance = distance - + add_to_header_nu = pe.Node(AddXFormToHeader(), name="Add_XForm_to_NU") add_to_header_nu.inputs.copy_name = True add_to_header_nu.inputs.out_file = 'nu.mgz' @@ -108,7 +108,7 @@ def create_AutoRecon2(name="AutoRecon2", longitudinal=False, ar2_wf.connect([(add_to_header_nu, align_transform, [('out_file', 'in_file')])]) else: ar2_wf.connect([(inputspec, align_transform, [('nu', 'in_file')])]) - + # CA Normalize """ @@ -698,7 +698,7 @@ def create_AutoRecon2(name="AutoRecon2", longitudinal=False, # add to outputspec to perserve datasinking ar2_wf.connect([(inputspec, outputspec, [('nu', 'nu')])]) - + ar2_wf.connect([(align_transform, outputspec, [('out_file', 'tal_lta')]), (ca_normalize, outputspec, [('out_file', 'norm')]), (ca_normalize, outputspec, [('control_points', 'ctrl_pts')]), diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index 359f311f2b..a4d5c5013c 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -621,10 +621,10 @@ def out_aseg(in_aparcaseg, in_aseg, out_file): out_aseg), name="Aseg") ar3_wf.connect([(aparc_2_aseg, apas_2_aseg, [('out_file', 'in_aparcaseg')]), - (inputspec, apas_2_aseg, [('aseg_presurf', 'in_aseg')])]) + (inputspec, apas_2_aseg, [('aseg_presurf', 'in_aseg')])]) apas_2_aseg.inputs.out_file = "aseg.mgz" - + # Segmentation Stats """ diff --git a/nipype/workflows/smri/freesurfer/ba_maps.py b/nipype/workflows/smri/freesurfer/ba_maps.py index 34c978c102..2e10c61e9e 100644 --- a/nipype/workflows/smri/freesurfer/ba_maps.py +++ b/nipype/workflows/smri/freesurfer/ba_maps.py @@ -85,7 +85,7 @@ def create_ba_maps_wf(name="Brodmann_Area_Maps", th3=True, exvivo=True, out_file = '{0}.{1}_exvivo.label'.format(hemisphere, label) else: out_file = '{0}.{1}.label'.format(hemisphere, label) - + out_files.append(out_file) field_template[label] = 'label/' + out_file source_fields.append(label) diff --git a/nipype/workflows/smri/freesurfer/recon.py b/nipype/workflows/smri/freesurfer/recon.py index f6996b6f2a..a4350ae425 100644 --- a/nipype/workflows/smri/freesurfer/recon.py +++ b/nipype/workflows/smri/freesurfer/recon.py @@ -167,7 +167,7 @@ def create_reconall_workflow(name="ReconAll", plugin_args=None, rb_date = "2008-03-26" print("FreeSurfer Version: {0}".format(fs_version)) - + def setconfig(reg_template=None, reg_template_withskull=None, lh_atlas=None, @@ -234,14 +234,14 @@ def checkarg(arg, default): 'lookup_table', 'wm_lookup_table', 'awk_file'] - + config_node = pe.Node(niu.Function(params + ['rb_date'], params, setconfig), name="config") config_node.inputs.rb_date = rb_date - + for param in params: reconall.connect(inputspec, param, config_node, param) From 959c57e71984b6d02e59054e76a23520db34fd03 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Wed, 13 Apr 2016 11:05:07 -0500 Subject: [PATCH 60/72] FIX: switches incorrect if statement. --- nipype/workflows/smri/freesurfer/autorecon3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index a4d5c5013c..04ab778609 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -936,7 +936,7 @@ def out_aseg(in_aparcaseg, in_aseg, out_file): (volume_mask, outputspec, [('out_ribbon', 'ribbon'), ('lh_ribbon', 'lh_ribbon'), ('rh_ribbon', 'rh_ribbon')])]) - if fsvernum < 6: + if fsvernum > 6: ar3_wf.connect([(relabel_hypos, outputspec, [('out_file', 'aseg_presurf_hypos')])]) From 56fbd21b250d15be361106fc0b469fe105031ae7 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Wed, 13 Apr 2016 15:02:52 -0500 Subject: [PATCH 61/72] FIX: Fixes aseg input for Aparc2Aseg. --- nipype/interfaces/freesurfer/utils.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/nipype/interfaces/freesurfer/utils.py b/nipype/interfaces/freesurfer/utils.py index 975dda9975..6f03a11f6e 100644 --- a/nipype/interfaces/freesurfer/utils.py +++ b/nipype/interfaces/freesurfer/utils.py @@ -2840,11 +2840,7 @@ def _format_arg(self, name, spec, value): if name == 'aseg': # aseg does not take a full filename basename = os.path.basename(value).replace('.mgz', '') - if basename != 'aseg': - return spec.argstr % basename - else: - # aseg.mgz is the default - return + return spec.argstr % basename elif name == 'out_file': return spec.argstr % os.path.abspath(value) From 3cd2fd0cfbed921453296fa6edf164f1f95b07fb Mon Sep 17 00:00:00 2001 From: David Ellis Date: Wed, 13 Apr 2016 15:39:36 -0500 Subject: [PATCH 62/72] FIX: Adds aseg input for a2009s Aparc2Aseg. --- nipype/workflows/smri/freesurfer/autorecon3.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index 04ab778609..1c49e56bd0 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -621,7 +621,8 @@ def out_aseg(in_aparcaseg, in_aseg, out_file): out_aseg), name="Aseg") ar3_wf.connect([(aparc_2_aseg, apas_2_aseg, [('out_file', 'in_aparcaseg')]), - (inputspec, apas_2_aseg, [('aseg_presurf', 'in_aseg')])]) + (inputspec, apas_2_aseg, [('aseg_presurf', 'in_aseg')]), + (inputspec, aparc_2_aseg_2009, [('aseg_presurf', 'aseg')])]) apas_2_aseg.inputs.out_file = "aseg.mgz" From 5644aa2b268f51a6eac5a935d0f40af6b6153107 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Wed, 13 Apr 2016 16:28:42 -0500 Subject: [PATCH 63/72] FIX: Adds stop and shrink values to autorecon2.py to ensure that the 6.0beta still works. --- nipype/workflows/smri/freesurfer/autorecon1.py | 2 +- nipype/workflows/smri/freesurfer/autorecon2.py | 3 ++- nipype/workflows/smri/freesurfer/recon.py | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon1.py b/nipype/workflows/smri/freesurfer/autorecon1.py index 161a690a9f..008563a737 100644 --- a/nipype/workflows/smri/freesurfer/autorecon1.py +++ b/nipype/workflows/smri/freesurfer/autorecon1.py @@ -36,7 +36,7 @@ def checkT1s(T1_files, cw256=False): return T1_files, cw256, resample_type, origvol_names def create_AutoRecon1(name="AutoRecon1", longitudinal=False, distance=200, - custom_atlas=None, plugin_args=None, shrink=2, stop=0.0001, + custom_atlas=None, plugin_args=None, shrink=None, stop=None, fsvernum=5.3): """Creates the AutoRecon1 workflow in nipype. diff --git a/nipype/workflows/smri/freesurfer/autorecon2.py b/nipype/workflows/smri/freesurfer/autorecon2.py index 3deabe6797..d3ff891af8 100644 --- a/nipype/workflows/smri/freesurfer/autorecon2.py +++ b/nipype/workflows/smri/freesurfer/autorecon2.py @@ -11,7 +11,8 @@ def copy_ltas(in_file, subjects_dir, subject_id, long_template): return out_file def create_AutoRecon2(name="AutoRecon2", longitudinal=False, - plugin_args=None, fsvernum=5.3): + plugin_args=None, fsvernum=5.3, + stop=None, shrink=None): # AutoRecon2 # Workflow ar2_wf = pe.Workflow(name=name) diff --git a/nipype/workflows/smri/freesurfer/recon.py b/nipype/workflows/smri/freesurfer/recon.py index a4350ae425..2943e7e800 100644 --- a/nipype/workflows/smri/freesurfer/recon.py +++ b/nipype/workflows/smri/freesurfer/recon.py @@ -259,7 +259,8 @@ def checkarg(arg, default): 'inputspec.reg_template_withskull'), ('awk_file', 'inputspec.awk_file')])]) # create AutoRecon2 - ar2_wf, ar2_outputs = create_AutoRecon2(plugin_args=plugin_args, fsvernum=fsvernum) + ar2_wf, ar2_outputs = create_AutoRecon2(plugin_args=plugin_args, fsvernum=fsvernum, + stop=stop, shrink=shrink) # connect inputs for AutoRecon2 reconall.connect([(inputspec, ar2_wf, [('num_threads', 'inputspec.num_threads')]), (config_node, ar2_wf, [('reg_template_withskull', From 095e3592def74332606b9b571037429a2fcf6a41 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Wed, 13 Apr 2016 16:40:01 -0500 Subject: [PATCH 64/72] FIX: Adds distance to autorecon2.py. --- nipype/workflows/smri/freesurfer/autorecon1.py | 2 +- nipype/workflows/smri/freesurfer/autorecon2.py | 2 +- nipype/workflows/smri/freesurfer/recon.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon1.py b/nipype/workflows/smri/freesurfer/autorecon1.py index 008563a737..0e11ab628c 100644 --- a/nipype/workflows/smri/freesurfer/autorecon1.py +++ b/nipype/workflows/smri/freesurfer/autorecon1.py @@ -35,7 +35,7 @@ def checkT1s(T1_files, cw256=False): resample_type = 'cubic' if len(T1_files) > 1 else 'interpolate' return T1_files, cw256, resample_type, origvol_names -def create_AutoRecon1(name="AutoRecon1", longitudinal=False, distance=200, +def create_AutoRecon1(name="AutoRecon1", longitudinal=False, distance=None, custom_atlas=None, plugin_args=None, shrink=None, stop=None, fsvernum=5.3): """Creates the AutoRecon1 workflow in nipype. diff --git a/nipype/workflows/smri/freesurfer/autorecon2.py b/nipype/workflows/smri/freesurfer/autorecon2.py index d3ff891af8..053bb2a9a2 100644 --- a/nipype/workflows/smri/freesurfer/autorecon2.py +++ b/nipype/workflows/smri/freesurfer/autorecon2.py @@ -12,7 +12,7 @@ def copy_ltas(in_file, subjects_dir, subject_id, long_template): def create_AutoRecon2(name="AutoRecon2", longitudinal=False, plugin_args=None, fsvernum=5.3, - stop=None, shrink=None): + stop=None, shrink=None, distance=None): # AutoRecon2 # Workflow ar2_wf = pe.Workflow(name=name) diff --git a/nipype/workflows/smri/freesurfer/recon.py b/nipype/workflows/smri/freesurfer/recon.py index 2943e7e800..9890380f94 100644 --- a/nipype/workflows/smri/freesurfer/recon.py +++ b/nipype/workflows/smri/freesurfer/recon.py @@ -260,7 +260,7 @@ def checkarg(arg, default): ('awk_file', 'inputspec.awk_file')])]) # create AutoRecon2 ar2_wf, ar2_outputs = create_AutoRecon2(plugin_args=plugin_args, fsvernum=fsvernum, - stop=stop, shrink=shrink) + stop=stop, shrink=shrink, distance=distance) # connect inputs for AutoRecon2 reconall.connect([(inputspec, ar2_wf, [('num_threads', 'inputspec.num_threads')]), (config_node, ar2_wf, [('reg_template_withskull', From 3f1926ca1433344226fe6e760bc0778da8639fb6 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Thu, 14 Apr 2016 16:13:16 -0500 Subject: [PATCH 65/72] FIX: Corrected fsvernum if statements to fix 6.0beta workflow. --- nipype/workflows/smri/freesurfer/autorecon2.py | 2 +- nipype/workflows/smri/freesurfer/autorecon3.py | 14 +++++--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon2.py b/nipype/workflows/smri/freesurfer/autorecon2.py index 053bb2a9a2..1e8ada6967 100644 --- a/nipype/workflows/smri/freesurfer/autorecon2.py +++ b/nipype/workflows/smri/freesurfer/autorecon2.py @@ -219,7 +219,7 @@ def create_AutoRecon2(name="AutoRecon2", longitudinal=False, fuse_segmentations.inputs.out_file = 'aseg.fused.mgz' ca_label = pe.Node(CALabel(), name='CA_Label') - if fsvernum > 6: + if fsvernum >= 6: ca_label.inputs.relabel_unlikely = (9, .3) ca_label.inputs.prior = 0.5 ca_label.inputs.align = True diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index 1c49e56bd0..5e74bc4103 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -286,7 +286,7 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, (ar3_rh_wf1, volume_mask, [('outputspec.pial', 'rh_pial')]), ]) - if fsvernum > 6: + if fsvernum >= 6: ar3_wf.connect([(inputspec, volume_mask, [('aseg_presurf', 'in_aseg')])]) else: ar3_wf.connect([(inputspec, volume_mask, [('aseg_presurf', 'aseg')])]) @@ -296,12 +296,8 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, for hemisphere, hemiwf2 in [('lh', ar3_lh_wf2), ('rh', ar3_rh_wf2)]: if hemisphere == 'lh': - opp_hemi = 'rh' - opp_wf = ar3_rh_wf2 hemiwf1 = ar3_lh_wf1 else: - opp_hemi = 'lh' - opp_wf = ar3_lh_wf2 hemiwf1 = ar3_rh_wf1 hemi_inputs2 = ['wm', @@ -603,7 +599,7 @@ def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, 'lh_ribbon'), ('out_ribbon', 'ribbon')])]) - if fsvernum > 6: + if fsvernum >= 6: apas_2_aseg = pe.Node(Apas2Aseg(), name="Apas_2_Aseg") ar3_wf.connect([(aparc_2_aseg, apas_2_aseg, [('out_file', 'in_file')]), (relabel_hypos, aparc_2_aseg_2009, [('out_file', 'aseg')])]) @@ -667,7 +663,7 @@ def out_aseg(in_aparcaseg, in_aseg, out_file): ]), ]) - if fsvernum > 6: + if fsvernum >= 6: ar3_wf.connect(inputspec, 'aseg_presurf', segstats, 'presurf_seg') else: ar3_wf.connect(inputspec, 'aseg_presurf', segstats, 'aseg') @@ -737,7 +733,7 @@ def out_aseg(in_aparcaseg, in_aseg, out_file): ]), ]) - if fsvernum > 6: + if fsvernum >= 6: ar3_wf.connect(inputspec, 'aseg_presurf', wm_segstats, 'presurf_seg') else: ar3_wf.connect(inputspec, 'aseg_presurf', wm_segstats, 'aseg') @@ -937,7 +933,7 @@ def out_aseg(in_aparcaseg, in_aseg, out_file): (volume_mask, outputspec, [('out_ribbon', 'ribbon'), ('lh_ribbon', 'lh_ribbon'), ('rh_ribbon', 'rh_ribbon')])]) - if fsvernum > 6: + if fsvernum >= 6: ar3_wf.connect([(relabel_hypos, outputspec, [('out_file', 'aseg_presurf_hypos')])]) From f88204e6af6b0f83e91ac4e4b5c5c7fbcec13b78 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Thu, 14 Apr 2016 16:36:27 -0500 Subject: [PATCH 66/72] FIX: Removes duplicate connection. --- nipype/workflows/smri/freesurfer/autorecon3.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index 5e74bc4103..ea315ecfad 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -715,7 +715,6 @@ def out_aseg(in_aparcaseg, in_aseg, out_file): ar3_wf.connect([(wm_parcellation, wm_segstats, [('out_file', 'segmentation_file')]), (inputspec, wm_segstats, [('lh_white', 'lh_white'), ('rh_white', 'rh_white'), - ('aseg_presurf', 'presurf_seg'), ('transform', 'transform'), ('norm', 'in_intensity'), ('norm', 'partial_volume_file'), From 58cfc19be098e698ef5857e28f0a8c00e3c316ff Mon Sep 17 00:00:00 2001 From: David Ellis Date: Fri, 15 Apr 2016 09:27:24 -0500 Subject: [PATCH 67/72] FIX: Changes list position of entorhinal. --- nipype/workflows/smri/freesurfer/ba_maps.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/workflows/smri/freesurfer/ba_maps.py b/nipype/workflows/smri/freesurfer/ba_maps.py index 2e10c61e9e..7fa266250c 100644 --- a/nipype/workflows/smri/freesurfer/ba_maps.py +++ b/nipype/workflows/smri/freesurfer/ba_maps.py @@ -58,7 +58,7 @@ def create_ba_maps_wf(name="Brodmann_Area_Maps", th3=True, exvivo=True, labels = ["BA1", "BA2", "BA3a", "BA3b", "BA4a", "BA4p", "BA6", "BA44", "BA45", "V1", "V2", "MT", "perirhinal"] if entorhinal: - labels.append('entorhinal') + labels.insert(-1, 'entorhinal') for hemisphere in ['lh', 'rh']: for threshold in [True, False]: field_template = dict(sphere_reg='surf/{0}.sphere.reg'.format(hemisphere), From 816f787e8c6cc57bc29baf43e7c379d5e19c7ac3 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Fri, 15 Apr 2016 11:10:03 -0500 Subject: [PATCH 68/72] DOC: Updates CHANGES --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index 337ae51f42..27c7ae31b7 100644 --- a/CHANGES +++ b/CHANGES @@ -28,6 +28,7 @@ Next release * FIX: Correct linking/copying fallback behavior (https://github.com/nipy/nipype/pull/1391) * ENH: Nipype workflow and interfaces for FreeSurfer's recon-all (https://github.com/nipy/nipype/pull/1326) * FIX: Permit relative path for concatenated_file input to Concatenate() (https://github.com/nipy/nipype/pull/1411) +* ENH: Makes ReconAll workflow backwards compatible with FreeSurfer 5.3.0 (https://github.com/nipy/nipype/pull/1434) Release 0.11.0 (September 15, 2015) ============ From 6437bf31405bda1d19eb40bb97eb2e8e3521218b Mon Sep 17 00:00:00 2001 From: David Ellis Date: Fri, 15 Apr 2016 15:03:22 -0500 Subject: [PATCH 69/72] FIX: Removes unnecessary methods from smri freesurfer workflow utils. --- .../smri/freesurfer/recode_tables/fs2abc.csv | 41 ---- nipype/workflows/smri/freesurfer/recon.py | 12 +- nipype/workflows/smri/freesurfer/utils.py | 209 ------------------ 3 files changed, 1 insertion(+), 261 deletions(-) delete mode 100644 nipype/workflows/smri/freesurfer/recode_tables/fs2abc.csv diff --git a/nipype/workflows/smri/freesurfer/recode_tables/fs2abc.csv b/nipype/workflows/smri/freesurfer/recode_tables/fs2abc.csv deleted file mode 100644 index 76035d3b51..0000000000 --- a/nipype/workflows/smri/freesurfer/recode_tables/fs2abc.csv +++ /dev/null @@ -1,41 +0,0 @@ -orig_label,target_label -41,1 -2,1 -42,2 -3,2 -77,2 -251,2 -252,2 -253,2 -254,2 -255,2 -43,4 -44,4 -4,4 -5,4 -14,4 -15,4 -24,4 -58,21 -50,21 -51,21 -52,21 -26,21 -11,21 -12,21 -13,21 -49,24 -60,24 -28,24 -10,24 -63,25 -53,25 -54,25 -31,25 -17,25 -18,25 -47,11 -8,11 -46,12 -7,12 -16,30 diff --git a/nipype/workflows/smri/freesurfer/recon.py b/nipype/workflows/smri/freesurfer/recon.py index b574314f35..0f1aad8913 100644 --- a/nipype/workflows/smri/freesurfer/recon.py +++ b/nipype/workflows/smri/freesurfer/recon.py @@ -79,8 +79,7 @@ def link_masks(subjects_dir, subject_id): wf.connect(autorecon_resume, "subject_id", outputnode, "subject_id") return wf -def create_reconall_workflow(name="ReconAll", plugin_args=None, - recoding_file=None): +def create_reconall_workflow(name="ReconAll", plugin_args=None): """Creates the ReconAll workflow in nipype. Example @@ -510,15 +509,6 @@ def completemethod(datasinked_files, subject_id): (inputspec, completion, [('subject_id', 'subject_id')]), (completion, postds_outputspec, [('subject_id', 'subject_id')])]) - - #### Workflow additions go here - if recoding_file: - from utils import create_recoding_wf - recode = create_recoding_wf(recoding_file) - reconall.connect([(ar3_wf, recode, [('outputspec.aseg', 'inputspec.labelmap')]), - (recode, outputspec, [('outputspec.recodedlabelmap', 'recoded_labelmap')])]) - - return reconall diff --git a/nipype/workflows/smri/freesurfer/utils.py b/nipype/workflows/smri/freesurfer/utils.py index 7ce98a4642..023cf612ec 100644 --- a/nipype/workflows/smri/freesurfer/utils.py +++ b/nipype/workflows/smri/freesurfer/utils.py @@ -493,79 +493,6 @@ def checkenv(exitonfail=False): else: print("Warning: " + msg) -def center_volume(in_file): - import SimpleITK as sitk - import os - img = sitk.ReadImage(in_file) - size = img.GetSize() - origin = img.GetOrigin() - new_origin = [0,0,0] - for i, xx in enumerate(origin): - new_origin[i] = float(size[i])/2 - if xx < 0: - new_origin[i] = -new_origin[i] - img.SetOrigin(new_origin) - out_file = os.path.abspath(os.path.basename(in_file)) - sitk.WriteImage(img, out_file) - return out_file - - -def recodeLabelMap(in_file, out_file, recode_file): - """This function has been adapted from BRAINSTools and serves - as a means to recode a label map based upon an input csv - file.""" - import SimpleITK as sitk - import os - import csv - import sys - - # Convert csv to RECODE_TABLE - CSVFile = open(recode_file, 'rb') - reader = csv.reader(CSVFile) - header = reader.next() - n_cols = len(header) - if n_cols == 4: - # ignore label names - label_keys = (0, 2) - elif n_cols == 2: - # no label names present - label_keys = (0, 1) - else: - # csv does not match format requirements - print("ERROR: input csv file for label recoding does meet requirements") - sys.exit() - - # read csv file - RECODE_TABLE = list() - for line in reader: - RECODE_TABLE.append((int(line[label_keys[0]]), int(line[label_keys[1]]))) - - def minimizeSizeOfImage(outlabels): - """This function will find the largest integer value in the labelmap, and - cast the image to the smallest possible integer size so that no loss of data - results.""" - measureFilt = sitk.StatisticsImageFilter() - measureFilt.Execute(outlabels) - imgMin=measureFilt.GetMinimum() - imgMax=measureFilt.GetMaximum() - if imgMax < (2**8)-1: - outlabels = sitk.Cast( outlabels, sitk.sitkUInt8 ) - elif imgMax < (2**16)-1: - outlabels = sitk.Cast( outlabels, sitk.sitkUInt16 ) - elif imgMax < (2**32)-1: - outlabels = sitk.Cast( outlabels, sitk.sitkUInt32 ) - elif imgMax < (2**64)-1: - outlabels = sitk.Cast( outlabels, sitk.sitkUInt64 ) - return outlabels - - LabelImage=sitk.Cast(sitk.ReadImage(in_file), sitk.sitkUInt32) - for (old, new) in RECODE_TABLE: - LabelImage = sitk.Cast((LabelImage == old), sitk.sitkUInt32)*(new - old)+LabelImage - LabelImage = minimizeSizeOfImage(LabelImage) - out_file = os.path.abspath(out_file) - sitk.WriteImage(LabelImage, out_file) - return out_file - def create_recoding_wf(in_file, out_file=None): wf = nipype.Workflow(name="RecodeLabels") @@ -729,139 +656,3 @@ def createsrcsubj(source_directory): rh_entorhinal_exvivo_thresh='label/rh.entorhinal_exvivo.thresh.label', rh_perirhinal_exvivo_thresh='label/rh.perirhinal_exvivo.thresh.label') return datasource, outfields - -def source_long_files_workflow(name="Source_Longitudinal_Files"): - """Creates a workflow to source the longitudinal files from a freesurfer directory. - This should only be used when the files are not in a prexisting workflow""" - - wf = Workflow(name=name) - - inputspec = Node(IdentityInterface(fields=['subject_id', - 'subjects_dir', - 'timepoints']), - name="inputspec") - - # TODO: Create outputspec - - # grab files from the initial single session run - grab_inittp_files = pe.Node(nio.DataGrabber(), name="Grab_Initial_Files", - infields=['subject_id'], - outfileds=['inputvols', 'iscales', 'ltas']) - grab_inittp_files.inputs.template = '*' - grab_inittp_files.inputs.base_directory = config['subjects_dir'] - grab_inittp_files.inputs.field_template = dict(inputvols='%s/mri/orig/0*.mgz', - iscales='%s/mri/orig/0*-iscale.txt', - ltas='%s/mri/orig/0*.lta') - - grab_inittp_files.inputs.template_args = dict(inputvols=[['subject_id']], - iscales=[['subject_id']], - ltas=[['subject_id']]) - - wf.connect([(grab_inittp_files, outputspec, [('inputvols', 'inputspec.in_T1s'), - ('iscales', 'inputspec.iscales'), - ('ltas', 'inputspec.ltas')])]) - - merge_norms = pe.Node(Merge(len(config['timepoints'])), name="Merge_Norms") - merge_segs = pe.Node(Merge(len(config['timepoints'])), name="Merge_Segmentations") - merge_segs_noCC = pe.Node(Merge(len(config['timepoints'])), name="Merge_Segmentations_noCC") - merge_template_ltas = pe.Node(Merge(len(config['timepoints'])), name="Merge_Template_ltas") - - for i, tp in enumerate(config['timepoints']): - # datasource timepoint files - tp_data_source = pe.Node(FreeSurferSource(), name="{0}_DataSource".format(tp)) - tp_data_source.inputs.subject_id = tp - tp_data_source.inputs.subjects_dir = config['subjects_dir'] - - tp_data_grabber = pe.Node(nio.DataGrabber(), name="{0}_DataGrabber".format(tp), - infields=['tp', 'long_tempate'], - outfileds=['subj_to_template_lta', 'seg_noCC', 'seg_presurf']) - tp_data_grabber.inputs.template = '*' - tp_data_grabber.inputs.base_directory = config['subjects_dir'] - tp_data_grabber.inputs.field_template = dict( - subj_to_template_lta='%s/mri/transforms/%s_to_%s.lta', - seg_noCC='%s/mri/aseg.auto_noCCseg.mgz', - seg_presurf='%s/mri/aseg.presurf.mgz',) - - tp_data_grabber.inputs.template_args = dict( - subj_to_template_lta=[['long_template', 'tp', 'long_template']], - seg_noCC=[['tp']], - seg_presurf=[['tp']]) - - wf.connect([(tp_data_source, merge_norms, [('norm', - 'in{0}'.format(i))]), - (tp_data_grabber, merge_segs, [('seg_presurf', - 'in{0}'.format(i))]), - (tp_data_grabber, merge_segs_noCC, [('seg_noCC', - 'in{0}'.format(i))]), - (tp_data_grabber, merge_template_ltas, [('subj_to_template_lta', - 'in{0}'.format(i))])]) - - if tp == config['subject_id']: - wf.connect([(tp_data_source, outputspec, [('wm', 'inputspec.init_wm')]), - (tp_data_grabber, outputspec, [('subj_to_template_lta', - 'inputspec.subj_to_template_lta')]), - (tp_data_grabber, outputspec, [('subj_to_template_lta', - 'inputspec.subj_to_template_lta')])]) - - wf.connect([(merge_norms, outputspec, [('out', 'inputspec.alltps_norms')]), - (merge_segs, outputspec, [('out', 'inputspec.alltps_segs')]), - (merge_template_ltas, outputspec, [('out', 'inputspec.alltps_to_template_ltas')]), - (merge_segs_noCC, outputspec, [('out', 'inputspec.alltps_segs_noCC')])]) - - - - # datasource files from the template run - ds_template_files = pe.Node(FreeSurferSource(), name="Datasource_Template_Files") - ds_template_files.inputs.subject_id = config['subject_id'] - ds_template_files.inputs.subjects_dir = config['subjects_dir'] - - wf.connect([(ds_template_files, ar1_wf, [('brainmask', 'inputspec.template_brainmask')]), - (ds_template_files, outputspec, [('aseg', 'inputspec.template_aseg')])]) - - # grab files from template run - grab_template_files = pe.Node(nio.DataGrabber(), name="Grab_Template_Files", - infields=['subject_id', 'long_template'], - outfields=['template_talairach_xfm', - 'template_talairach_lta', - 'template_talairach_m3z', - 'template_label_intensities', - 'template_lh_white', - 'template_rh_white', - 'template_lh_pial', - 'template_rh_pial']) - grab_template_files.inputs.template = '*' - grab_template_files.inputs.base_directory = config['subjects_dir'] - grab_template_files.inputs.subject_id = config['subject_id'] - grab_template_files.inputs.long_template = config['long_template'] - grab_template_files.inputs.field_template = dict( - template_talairach_xfm='%s/mri/transfroms/talairach.xfm', - template_talairach_lta='%s/mri/transfroms/talairach.lta', - template_talairach_m3z='%s/mri/transfroms/talairach.m3z', - template_label_intensities='%s/mri/aseg.auto_noCCseg.label_intensities.txt', - template_lh_white='%s/surf/lh.white', - template_rh_white='%s/surf/rh.white', - template_lh_pial='%s/surf/lh.pial', - template_rh_pial='%s/surf/rh.pial') - - grab_template_files.inputs.template_args = dict( - template_talairach_xfm=[['long_template']], - template_talairach_lta=[['long_template']], - template_talairach_m3z=[['long_template']], - template_lh_white=[['long_template']], - template_rh_white=[['long_template']], - template_lh_pial=[['long_template']], - template_rh_pial=[['long_template']]) - wf.connect([(grab_template_files, outputspec, [('template_talairach_xfm', - 'inputspec.template_talairach_xfm'), - ('template_talairach_lta', - 'inputspec.template_talairach_lta'), - ('template_talairach_m3z', - 'inputspec.template_talairach_m3z'), - ('template_label_intensities', - 'inputspec.template_label_intensities'), - ('template_lh_white', 'inputspec.template_lh_white'), - ('template_rh_white', 'inputspec.template_rh_white'), - ('template_lh_pial', 'inputspec.template_lh_pial'), - ('template_rh_pial', 'inputspec.template_rh_pial')]) - ]) - return wf From c39acaf35ea58afc620e8b49b2768b1b25ceacc6 Mon Sep 17 00:00:00 2001 From: David Ellis Date: Fri, 15 Apr 2016 16:56:42 -0500 Subject: [PATCH 70/72] FIX: Removes unused functions and imports. --- .../workflows/smri/freesurfer/autorecon1.py | 5 +- .../workflows/smri/freesurfer/autorecon2.py | 2 - .../workflows/smri/freesurfer/autorecon3.py | 5 +- nipype/workflows/smri/freesurfer/utils.py | 164 ------------------ 4 files changed, 2 insertions(+), 174 deletions(-) diff --git a/nipype/workflows/smri/freesurfer/autorecon1.py b/nipype/workflows/smri/freesurfer/autorecon1.py index b77b65465c..e29a949166 100644 --- a/nipype/workflows/smri/freesurfer/autorecon1.py +++ b/nipype/workflows/smri/freesurfer/autorecon1.py @@ -1,10 +1,7 @@ -import sys -import os -import nipype from nipype.interfaces.utility import Function,IdentityInterface import nipype.pipeline.engine as pe # pypeline engine from nipype.interfaces.freesurfer import * -from .utils import copy_file, copy_files +from .utils import copy_file def checkT1s(T1_files, cw256=False): diff --git a/nipype/workflows/smri/freesurfer/autorecon2.py b/nipype/workflows/smri/freesurfer/autorecon2.py index 2fd85bce13..f09e991439 100644 --- a/nipype/workflows/smri/freesurfer/autorecon2.py +++ b/nipype/workflows/smri/freesurfer/autorecon2.py @@ -1,5 +1,3 @@ -import os -import nipype from nipype.interfaces.utility import Function, IdentityInterface, Merge import nipype.pipeline.engine as pe # pypeline engine from nipype.interfaces.freesurfer import * diff --git a/nipype/workflows/smri/freesurfer/autorecon3.py b/nipype/workflows/smri/freesurfer/autorecon3.py index ffc0eec7b9..656f81188e 100644 --- a/nipype/workflows/smri/freesurfer/autorecon3.py +++ b/nipype/workflows/smri/freesurfer/autorecon3.py @@ -1,10 +1,7 @@ -import os -import nipype -from nipype.interfaces.utility import Function, IdentityInterface, Merge +from nipype.interfaces.utility import IdentityInterface, Merge import nipype.pipeline.engine as pe # pypeline engine from nipype.interfaces.freesurfer import * from .ba_maps import create_ba_maps_wf -from .utils import createsrcsubj from nipype.interfaces.io import DataGrabber def create_AutoRecon3(name="AutoRecon3", qcache=False, plugin_args=None, diff --git a/nipype/workflows/smri/freesurfer/utils.py b/nipype/workflows/smri/freesurfer/utils.py index 023cf612ec..74d45776d2 100644 --- a/nipype/workflows/smri/freesurfer/utils.py +++ b/nipype/workflows/smri/freesurfer/utils.py @@ -492,167 +492,3 @@ def checkenv(exitonfail=False): sys.exit(2) else: print("Warning: " + msg) - - -def create_recoding_wf(in_file, out_file=None): - wf = nipype.Workflow(name="RecodeLabels") - - inputspec = nipype.pipeline.Node(nipype.IdentityInterface(['labelmap', - 'recode_file']), - name="inputspec") - inputspec.inputs.recode_file = in_file - - convert_labelmap = nipype.pipeline.Node(fs.MRIConvert(), name="ConvertLabelMap") - convert_labelmap.inputs.in_type = 'mgz' - convert_labelmap.inputs.out_type = 'nii' - convert_labelmap.inputs.out_orientation = 'RAS' - convert_labelmap.inputs.out_file = 'labelmap.nii' - wf.connect([(inputspec, convert_labelmap, [('labelmap', 'in_file')])]) - - recode = nipype.Node(nipype.Function(['in_file', - 'out_file', - 'recode_file'], - ['out_file'], - recodeLabelMap), - name = "RecodeLabelMap") - if out_file == None: - recode.inputs.out_file = 'recodedlabelmap.nii' - else: - recode.inputs.out_file = out_file - - wf.connect([(convert_labelmap, recode, [('out_file', 'in_file')]), - (inputspec, recode, [('recode_file', 'recode_file')])]) - - center_labelmap = nipype.Node(nipype.Function(['in_file'], ['out_file'], - center_volume), - name="CenterLabelMap") - - wf.connect([(recode, center_labelmap, [('out_file', 'in_file')])]) - - outputspec = nipype.Node(nipype.IdentityInterface(['recodedlabelmap']), name="outputspec") - - wf.connect([(center_labelmap, outputspec, [('out_file', 'recodedlabelmap')])]) - return wf - -def createsrcsubj(source_directory): - """ - Returns a node that acts as the datasource for a source subject such as - 'fsaverage' - """ - outfields = ['lh_BA1_exvivo', - 'lh_BA2_exvivo', - 'lh_BA3a_exvivo', - 'lh_BA3b_exvivo', - 'lh_BA4a_exvivo', - 'lh_BA4p_exvivo', - 'lh_BA6_exvivo', - 'lh_BA44_exvivo', - 'lh_BA45_exvivo', - 'lh_V1_exvivo', - 'lh_V2_exvivo', - 'lh_MT_exvivo', - 'lh_entorhinal_exvivo', - 'lh_perirhinal_exvivo', - 'lh_BA1_exvivo_thresh', - 'lh_BA2_exvivo_thresh', - 'lh_BA3a_exvivo_thresh', - 'lh_BA3b_exvivo_thresh', - 'lh_BA4a_exvivo_thresh', - 'lh_BA4p_exvivo_thresh', - 'lh_BA6_exvivo_thresh', - 'lh_BA44_exvivo_thresh', - 'lh_BA45_exvivo_thresh', - 'lh_V1_exvivo_thresh', - 'lh_V2_exvivo_thresh', - 'lh_MT_exvivo_thresh', - 'lh_entorhinal_exvivo_thresh', - 'lh_perirhinal_exvivo_thresh', - 'rh_BA1_exvivo', - 'rh_BA2_exvivo', - 'rh_BA3a_exvivo', - 'rh_BA3b_exvivo', - 'rh_BA4a_exvivo', - 'rh_BA4p_exvivo', - 'rh_BA6_exvivo', - 'rh_BA44_exvivo', - 'rh_BA45_exvivo', - 'rh_V1_exvivo', - 'rh_V2_exvivo', - 'rh_MT_exvivo', - 'rh_entorhinal_exvivo', - 'rh_perirhinal_exvivo', - 'rh_BA1_exvivo_thresh', - 'rh_BA2_exvivo_thresh', - 'rh_BA3a_exvivo_thresh', - 'rh_BA3b_exvivo_thresh', - 'rh_BA4a_exvivo_thresh', - 'rh_BA4p_exvivo_thresh', - 'rh_BA6_exvivo_thresh', - 'rh_BA44_exvivo_thresh', - 'rh_BA45_exvivo_thresh', - 'rh_V1_exvivo_thresh', - 'rh_V2_exvivo_thresh', - 'rh_MT_exvivo_thresh', - 'rh_entorhinal_exvivo_thresh', - 'rh_perirhinal_exvivo_thresh'] - datasource = pe.Node(nio.nio.DataGrabber(outfields=outfields), name="Source_Subject") - datasource.inputs.base_directory = source_directory - datasource.inputs.template = '*' - datasource.inputs.field_template = dict( - lh_BA1_exvivo='label/lh.BA1_exvivo.label', - lh_BA2_exvivo='label/lh.BA2_exvivo.label', - lh_BA3a_exvivo='label/lh.BA3a_exvivo.label', - lh_BA3b_exvivo='label/lh.BA3b_exvivo.label', - lh_BA4a_exvivo='label/lh.BA4a_exvivo.label', - lh_BA4p_exvivo='label/lh.BA4p_exvivo.label', - lh_BA6_exvivo='label/lh.BA6_exvivo.label', - lh_BA44_exvivo='label/lh.BA44_exvivo.label', - lh_BA45_exvivo='label/lh.BA45_exvivo.label', - lh_V1_exvivo='label/lh.V1_exvivo.label', - lh_V2_exvivo='label/lh.V2_exvivo.label', - lh_MT_exvivo='label/lh.MT_exvivo.label', - lh_entorhinal_exvivo='label/lh.entorhinal_exvivo.label', - lh_perirhinal_exvivo='label/lh.perirhinal_exvivo.label', - lh_BA1_exvivo_thresh='label/lh.BA1_exvivo.thresh.label', - lh_BA2_exvivo_thresh='label/lh.BA2_exvivo.thresh.label', - lh_BA3a_exvivo_thresh='label/lh.BA3a_exvivo.thresh.label', - lh_BA3b_exvivo_thresh='label/lh.BA3b_exvivo.thresh.label', - lh_BA4a_exvivo_thresh='label/lh.BA4a_exvivo.thresh.label', - lh_BA4p_exvivo_thresh='label/lh.BA4p_exvivo.thresh.label', - lh_BA6_exvivo_thresh='label/lh.BA6_exvivo.thresh.label', - lh_BA44_exvivo_thresh='label/lh.BA44_exvivo.thresh.label', - lh_BA45_exvivo_thresh='label/lh.BA45_exvivo.thresh.label', - lh_V1_exvivo_thresh='label/lh.V1_exvivo.thresh.label', - lh_V2_exvivo_thresh='label/lh.V2_exvivo.thresh.label', - lh_MT_exvivo_thresh='label/lh.MT_exvivo.thresh.label', - lh_entorhinal_exvivo_thresh='label/lh.entorhinal_exvivo.thresh.label', - lh_perirhinal_exvivo_thresh='label/lh.perirhinal_exvivo.thresh.label', - rh_BA1_exvivo='label/rh.BA1_exvivo.label', - rh_BA2_exvivo='label/rh.BA2_exvivo.label', - rh_BA3a_exvivo='label/rh.BA3a_exvivo.label', - rh_BA3b_exvivo='label/rh.BA3b_exvivo.label', - rh_BA4a_exvivo='label/rh.BA4a_exvivo.label', - rh_BA4p_exvivo='label/rh.BA4p_exvivo.label', - rh_BA6_exvivo='label/rh.BA6_exvivo.label', - rh_BA44_exvivo='label/rh.BA44_exvivo.label', - rh_BA45_exvivo='label/rh.BA45_exvivo.label', - rh_V1_exvivo='label/rh.V1_exvivo.label', - rh_V2_exvivo='label/rh.V2_exvivo.label', - rh_MT_exvivo='label/rh.MT_exvivo.label', - rh_entorhinal_exvivo='label/rh.entorhinal_exvivo.label', - rh_perirhinal_exvivo='label/rh.perirhinal_exvivo.label', - rh_BA1_exvivo_thresh='label/rh.BA1_exvivo.thresh.label', - rh_BA2_exvivo_thresh='label/rh.BA2_exvivo.thresh.label', - rh_BA3a_exvivo_thresh='label/rh.BA3a_exvivo.thresh.label', - rh_BA3b_exvivo_thresh='label/rh.BA3b_exvivo.thresh.label', - rh_BA4a_exvivo_thresh='label/rh.BA4a_exvivo.thresh.label', - rh_BA4p_exvivo_thresh='label/rh.BA4p_exvivo.thresh.label', - rh_BA6_exvivo_thresh='label/rh.BA6_exvivo.thresh.label', - rh_BA44_exvivo_thresh='label/rh.BA44_exvivo.thresh.label', - rh_BA45_exvivo_thresh='label/rh.BA45_exvivo.thresh.label', - rh_V1_exvivo_thresh='label/rh.V1_exvivo.thresh.label', - rh_V2_exvivo_thresh='label/rh.V2_exvivo.thresh.label', - rh_MT_exvivo_thresh='label/rh.MT_exvivo.thresh.label', - rh_entorhinal_exvivo_thresh='label/rh.entorhinal_exvivo.thresh.label', - rh_perirhinal_exvivo_thresh='label/rh.perirhinal_exvivo.thresh.label') - return datasource, outfields From 461b17b639482518ba2e5d4eee3a7886226408fb Mon Sep 17 00:00:00 2001 From: Alexandre Manhaes Savio Date: Thu, 7 Apr 2016 14:05:45 +0200 Subject: [PATCH 71/72] add nipype_crash_search script --- bin/nipype_crash_search.py | 76 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100755 bin/nipype_crash_search.py diff --git a/bin/nipype_crash_search.py b/bin/nipype_crash_search.py new file mode 100755 index 0000000000..068e5d600a --- /dev/null +++ b/bin/nipype_crash_search.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +"""Search for tracebacks inside a folder of nipype crash +log files that match a given regular expression. + +Examples: +nipype_crash_search -d nipype/wd/log -r '.*subject123.*' +""" +import re +import os.path as op +from glob import glob + +from traits.trait_errors import TraitError +from nipype.utils.filemanip import loadcrash + + +def load_pklz_traceback(crash_filepath): + """ Return the traceback message in the given crash file.""" + try: + data = loadcrash(crash_filepath) + except TraitError as te: + return str(te) + except: + raise + else: + return '\n'.join(data['traceback']) + + +def iter_tracebacks(logdir): + """ Return an iterator over each file path and + traceback field inside `logdir`. + Parameters + ---------- + logdir: str + Path to the log folder. + + field: str + Field name to be read from the crash file. + + Yields + ------ + path_file: str + + traceback: str + """ + crash_files = sorted(glob(op.join(logdir, '*.pkl*'))) + + for cf in crash_files: + yield cf, load_pklz_traceback(cf) + + +def display_crash_search(logdir, regex): + rex = re.compile(regex, re.IGNORECASE) + for file, trace in iter_tracebacks(logdir): + if rex.search(trace): + print("-" * len(file)) + print(file) + print("-" * len(file)) + print(trace) + + +if __name__ == "__main__": + from argparse import ArgumentParser, RawTextHelpFormatter + defstr = ' (default %(default)s)' + parser = ArgumentParser(prog='nipype_crash_search', + description=__doc__, + formatter_class=RawTextHelpFormatter) + parser.add_argument('-l','--logdir', type=str, dest='logdir', + action="store", default=None, + help='The working directory log file.' + defstr) + parser.add_argument('-r', '--regex', dest='regex', + default='*', + help='Regular expression to be searched in each traceback.' + defstr) + + args = parser.parse_args() + + display_crash_search(args.logdir, args.regex) From d76723295fc3feb1887c09aa003bf2ce14ac2353 Mon Sep 17 00:00:00 2001 From: Alexandre Manhaes Savio Date: Mon, 18 Apr 2016 11:18:23 +0200 Subject: [PATCH 72/72] add doc for nipype_crash_search --- CHANGES | 1 + CHANGES.orig | 538 -------------------------------------------- doc/users/debug.rst | 3 + 3 files changed, 4 insertions(+), 538 deletions(-) delete mode 100644 CHANGES.orig diff --git a/CHANGES b/CHANGES index 27c7ae31b7..5c927ac77c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,7 @@ Next release ============ +* ENH: Add nipype_crash_search command (https://github.com/nipy/nipype/pull/1422) * ENH: Created interface for BrainSuite Cortical Surface Extraction command line tools (https://github.com/nipy/nipype/pull/1305) * FIX: job execution on systems/approaches where locale is undefined (https://github.com/nipy/nipype/pull/1401) * FIX: Clean up byte/unicode issues using subprocess (https://github.com/nipy/nipype/pull/1394) diff --git a/CHANGES.orig b/CHANGES.orig deleted file mode 100644 index b7a849dd7e..0000000000 --- a/CHANGES.orig +++ /dev/null @@ -1,538 +0,0 @@ -Next release -============ - -* FIX: job execution on systems/approaches where locale is undefined (https://github.com/nipy/nipype/pull/1401) -* FIX: Clean up byte/unicode issues using subprocess (https://github.com/nipy/nipype/pull/1394) -* FIX: Prevent crash when tvtk is loaded - ETS_TOOLKIT=null (https://github.com/nipy/nipype/pull/973) -* ENH: New interfaces in dipy: RESTORE, EstimateResponseSH, CSD and StreamlineTractography - (https://github.com/nipy/nipype/pull/1090) -* ENH: Added interfaces of AFNI (https://github.com/nipy/nipype/pull/1360, - https://github.com/nipy/nipype/pull/1361, https://github.com/nipy/nipype/pull/1382) -* ENH: Provides a Nipype wrapper for antsJointFusion (https://github.com/nipy/nipype/pull/1351) -* ENH: Added support for PETPVC (https://github.com/nipy/nipype/pull/1335) -* ENH: Merge S3DataSink into DataSink, added AWS documentation (https://github.com/nipy/nipype/pull/1316) -* TST: Cache APT in CircleCI (https://github.com/nipy/nipype/pull/1333) -* ENH: Add new flags to the BRAINSABC for new features (https://github.com/nipy/nipype/pull/1322) -* ENH: Provides a Nipype wrapper for ANTs DenoiseImage (https://github.com/nipy/nipype/pull/1291) -* FIX: Minor bugfix logging hash differences (https://github.com/nipy/nipype/pull/1298) -* FIX: Use released Prov python library (https://github.com/nipy/nipype/pull/1279) -* ENH: Support for Python 3 (https://github.com/nipy/nipype/pull/1221) -* FIX: VTK version check missing when using tvtk (https://github.com/nipy/nipype/pull/1219) -* ENH: Added an OAR scheduler plugin (https://github.com/nipy/nipype/pull/1259) -* ENH: New ANTs interface: antsBrainExtraction (https://github.com/nipy/nipype/pull/1231) -* API: Default model level for the bedpostx workflow has been set to "2" following FSL 5.0.9 lead -* ENH: New interfaces for interacting with AWS S3: S3DataSink and S3DataGrabber (https://github.com/nipy/nipype/pull/1201) -* ENH: Interfaces for MINC tools (https://github.com/nipy/nipype/pull/1304) -* FIX: Use realpath to determine hard link source (https://github.com/nipy/nipype/pull/1388) -* FIX: Correct linking/copying fallback behavior (https://github.com/nipy/nipype/pull/1391) -* ENH: Nipype workflow and interfaces for FreeSurfer's recon-all (https://github.com/nipy/nipype/pull/1326) -======= - -Release 0.11.0 (September 15, 2015) -============ - -* API: Change how hash values are computed (https://github.com/nipy/nipype/pull/1174) -* ENH: New algorithm: mesh.WarpPoints applies displacements fields to point sets - (https://github.com/nipy/nipype/pull/889). -* ENH: New interfaces for MRTrix3 (https://github.com/nipy/nipype/pull/1126) -* ENH: New option in afni.3dRefit - zdel, ydel, zdel etc. (https://github.com/nipy/nipype/pull/1079) -* FIX: ants.Registration composite transform outputs are no longer returned as lists (https://github.com/nipy/nipype/pull/1183) -* BUG: ANTs Registration interface failed with multi-modal inputs - (https://github.com/nipy/nipype/pull/1176) (https://github.com/nipy/nipype/issues/1175) -* ENH: dipy.TrackDensityMap interface now accepts a reference image (https://github.com/nipy/nipype/pull/1091) -* FIX: Bug in XFibres5 (https://github.com/nipy/nipype/pull/1168) -* ENH: Attempt to use hard links for data sink. - (https://github.com/nipy/nipype/pull/1161) -* FIX: Updates to SGE Plugins - (https://github.com/nipy/nipype/pull/1129) -* ENH: Add ants JointFusion() node with testing - (https://github.com/nipy/nipype/pull/1160) -* ENH: Add --float option for antsRegistration calls - (https://github.com/nipy/nipype/pull/1159) -* ENH: Added interface to simulate DWIs using the multi-tensor model - (https://github.com/nipy/nipype/pull/1085) -* ENH: New interface for FSL fslcpgeom utility (https://github.com/nipy/nipype/pull/1152) -* ENH: Added SLURMGraph plugin for submitting jobs to SLURM with dependencies (https://github.com/nipy/nipype/pull/1136) -* FIX: Enable absolute path definitions in DCMStack (https://github.com/nipy/nipype/pull/1089, - replaced by https://github.com/nipy/nipype/pull/1093) -* ENH: New mesh.MeshWarpMaths to operate on surface-defined warpings - (https://github.com/nipy/nipype/pull/1016) -* FIX: Refactor P2PDistance, change name to ComputeMeshWarp, add regression tests, - fix bug in area weighted distance, and added optimizations - (https://github.com/nipy/nipype/pull/1016) -* ENH: Add an option not to resubmit Nodes that finished running when using SGEGraph (https://github.com/nipy/nipype/pull/1002) -* FIX: FUGUE is now properly listing outputs. (https://github.com/nipy/nipype/pull/978) -* ENH: Improved FieldMap-Based (FMB) workflow for correction of susceptibility distortions in EPI seqs. - (https://github.com/nipy/nipype/pull/1019) -* FIX: In the FSLXcommand _list_outputs function fixed for loop range (https://github.com/nipy/nipype/pull/1071) -* ENH: Dropped support for now 7 years old Python 2.6 (https://github.com/nipy/nipype/pull/1069) -* FIX: terminal_output is not mandatory anymore (https://github.com/nipy/nipype/pull/1070) -* ENH: Added "nipype_cmd" tool for running interfaces from the command line (https://github.com/nipy/nipype/pull/795) -* FIX: Fixed Camino output naming (https://github.com/nipy/nipype/pull/1061) -* ENH: Add the average distance to ErrorMap (https://github.com/nipy/nipype/pull/1039) -* ENH: Inputs with name_source can be now chained in cascade (https://github.com/nipy/nipype/pull/938) -* ENH: Improve JSON interfaces: default settings when reading and consistent output creation - when writing (https://github.com/nipy/nipype/pull/1047) -* FIX: AddCSVRow problems when using infields (https://github.com/nipy/nipype/pull/1028) -* FIX: Removed unused ANTS registration flag (https://github.com/nipy/nipype/pull/999) -* FIX: Amend create_tbss_non_fa() workflow to match FSL's tbss_non_fa command. (https://github.com/nipy/nipype/pull/1033) -* FIX: remove unused mandatory flag from spm normalize (https://github.com/nipy/nipype/pull/1048) -* ENH: Update ANTSCorticalThickness interface (https://github.com/nipy/nipype/pull/1013) -* FIX: Edge case with sparsemodels and PEP8 cleanup (https://github.com/nipy/nipype/pull/1046) -* ENH: New io interfaces for JSON files reading/writing (https://github.com/nipy/nipype/pull/1020) -* ENH: Enhanced openfmri script to support freesurfer linkage (https://github.com/nipy/nipype/pull/1037) -* BUG: matplotlib is supposed to be optional (https://github.com/nipy/nipype/pull/1003) -* FIX: Fix split_filename behaviour when path has no file component (https://github.com/nipy/nipype/pull/1035) -* ENH: Updated FSL dtifit to include option for grad non-linearities (https://github.com/nipy/nipype/pull/1032) -* ENH: Updated Camino tracking interfaces, which can now use FSL bedpostx output. - New options also include choice of tracker, interpolator, stepsize and - curveinterval for angle threshold (https://github.com/nipy/nipype/pull/1029) -* FIX: Interfaces redirecting X crashed if $DISPLAY not defined (https://github.com/nipy/nipype/pull/1027) -* FIX: Bug crashed 'make api' (https://github.com/nipy/nipype/pull/1026) -* ENH: Updated antsIntroduction to handle RA and RI registrations (https://github.com/nipy/nipype/pull/1009) -* ENH: Updated N4BiasCorrection input spec to include weight image and spline order. Made - argument formatting consistent. Cleaned ants.segmentation according to PEP8. - (https://github.com/nipy/nipype/pull/990/files) -* ENH: SPM12 Normalize interface (https://github.com/nipy/nipype/pull/986) -* FIX: Utility interface test dir (https://github.com/nipy/nipype/pull/986) -* FIX: IPython engine directory reset after crash (https://github.com/nipy/nipype/pull/987) -* ENH: Resting state fMRI example with NiPy realignment and no SPM (https://github.com/nipy/nipype/pull/992) -* FIX: Corrected Freesurfer SegStats _list_outputs to avoid error if summary_file is - undefined (issue #994)(https://https://github.com/nipy/nipype/pull/996) -* FIX: OpenfMRI support and FSL 5.0.7 changes (https://github.com/nipy/nipype/pull/1006) -* FIX: Output prefix in SPM Normalize with modulation (https://github.com/nipy/nipype/pull/1023) -* ENH: Usability improvements in cluster environments (https://github.com/nipy/nipype/pull/1025) -* ENH: ANTs JointFusion() (https://github.com/nipy/nipype/pull/1042) -* ENH: Added csvReader() utility (https://github.com/nipy/nipype/pull/1044) -* FIX: typo in nipype.interfaces.freesurfer.utils.py Tkregister2 (https://github.com/nipy/nipype/pull/1083) -* FIX: SSHDataGrabber outputs now return full path to the grabbed/downloaded files. (https://github.com/nipy/nipype/pull/1086) -* FIX: Add QA output for TSNR to resting workflow (https://github.com/nipy/nipype/pull/1088) -* FIX: Change N4BiasFieldCorrection to use short tag for dimensionality (backward compatible) (https://github.com/nipy/nipype/pull/1096) -* ENH: Added -newgrid input to Warp in AFNI (3dWarp wrapper) (https://github.com/nipy/nipype/pull/1128) -* FIX: Fixed AFNI Copy interface to use positional inputs as required (https://github.com/nipy/nipype/pull/1131) -* ENH: Added a check in Dcm2nii to check if nipype created the config.ini file and remove if true (https://github.com/nipy/nipype/pull/1132) -* ENH: Use a while loop to wait for Xvfb (up to a max wait time "xvfb_max_wait" in config file, default 10) - (https://github.com/nipy/nipype/pull/1142) - -Release 0.10.0 (October 10, 2014) -============ - -* ENH: New miscelaneous interfaces: SplitROIs (mapper), MergeROIs (reducer) - to enable parallel processing of very large images. -* ENH: Updated FSL interfaces: BEDPOSTX and XFibres, former interfaces are still - available with the version suffix: BEDPOSTX4 and XFibres4. Added gpu - versions of BEDPOSTX: BEDPOSTXGPU, BEDPOSTX5GPU, and BEDPOSTX4GPU -* ENH: Added experimental support for MIPAV algorithms thorugh JIST plugins -* ENH: New dipy interfaces: Denoise, Resample -* ENH: New Freesurfer interfaces: Tkregister2 (for conversion of fsl style matrices to freesurfer format), MRIPretess -* ENH: New FSL interfaces: WarpPoints, WarpPointsToStd, EpiReg, ProbTrackX2, WarpUtils, ConvertWarp -* ENH: New miscelaneous interfaces: AddCSVRow, NormalizeProbabilityMapSet, AddNoise -* ENH: New AFNI interfaces: Eval, Means, SVMTest, SVMTrain -* ENH: FUGUE interface has been refactored to use the name_template system, 3 examples - added to doctests, some bugs solved. -* API: Interfaces to external packages are no longer available in the top-level - ``nipype`` namespace, and must be imported directly (e.g. - ``from nipype.interfaces import fsl``). -* ENH: Support for elastix via a set of new interfaces: Registration, ApplyWarp, - AnalyzeWarp, PointsWarp, and EditTransform -* ENH: New ANTs interface: ApplyTransformsToPoints, LaplacianThickness -* ENH: New Diffusion Toolkit interface: TrackMerge -* ENH: New MRtrix interface: FilterTracks -* ENH: New metrics group in algorithms. Now Distance, Overlap, and FuzzyOverlap - are found in nipype.algorithms.metrics instead of misc. Overlap interface - extended to allow files containing multiple ROIs and volume physical units. -* ENH: New interface in algorithms.metrics: ErrorMap (a voxel-wise diff map). -* ENH: New FreeSurfer workflow: create_skullstripped_recon_flow() -* ENH: Deep revision of workflows for correction of dMRI artifacts. New dmri_preprocessing - example. -* ENH: New data grabbing interface that works over SSH connections, SSHDataGrabber -* ENH: New color mode for write_graph -* ENH: You can now force MapNodes to be run serially -* ENH: Added ANTS based openfmri workflow -* ENH: MapNode now supports flattening of nested lists -* ENH: Support for headless mode using Xvfb -* ENH: nipype_display_crash has a debugging mode -* FIX: MRTrix tracking algorithms were ignoring mask parameters. -* FIX: FNIRT registration pathway and associated OpenFMRI example script -* FIX: spm12b compatibility for Model estimate -* FIX: Batch scheduler controls the number of maximum jobs properly -* FIX: Update for FSL 5.0.7 which deprecated Contrast Manager - -Release 0.9.2 (January 31, 2014) -============ - -* FIX: DataFinder was broken due to a typo -* FIX: Order of DataFinder outputs was not guaranteed, it's human sorted now -* ENH: New interfaces: Vnifti2Image, VtoMat - -Release 0.9.1 (December 25, 2013) -============ - -* FIX: installation issues - -Release 0.9.0 (December 20, 2013) -============ - -* ENH: SelectFiles: a streamlined version of DataGrabber -* ENH: new tools for defining workflows: JoinNode, synchronize and itersource -* ENH: W3C PROV support with optional RDF export built into Nipype -* ENH: Added support for Simple Linux Utility Resource Management (SLURM) -* ENH: AFNI interfaces refactor, prefix, suffix are replaced by - "flexible_%s_templates" -* ENH: New SPM interfaces: - - spm.ResliceToReference, - - spm.DicomImport -* ENH: New AFNI interfaces: - - afni.AFNItoNIFTI - - afni.TCorr1D -* ENH: Several new interfaces related to Camino were added: - - camino.SFPICOCalibData - - camino.Conmat - - camino.QBallMX - - camino.LinRecon - - camino.SFPeaks - One outdated interface no longer part of Camino was removed: - - camino.Conmap -* ENH: Three new mrtrix interfaces were added: - - mrtrix.GenerateDirections - - mrtrix.FindShPeaks - - mrtrix.Directions2Amplitude -* ENH: New FSL interfaces: - - fsl.PrepareFieldmap - - fsl.TOPUP - - fsl.ApplyTOPUP - - fsl.Eddy -* ENH: New misc interfaces: - - FuzzyOverlap, - - P2PDistance -* ENH: New workflows: nipype.workflows.dmri.fsl.epi.[fieldmap_correction&topup_correction] -* ENH: Added simplified outputname generation for command line interfaces. -* ENH: Allow ants use a single mask image -* ENH: Create configuration option for parameterizing directories with hashes -* ENH: arrange nodes by topological sort with disconnected subgraphs -* ENH: uses the nidm iri namespace for uuids -* ENH: remove old reporting webpage -* ENH: Added support for Vagrant - -* API: 'name' is now a positional argument for Workflow, Node, and MapNode constructors -* API: SPM now defaults to SPM8 or SPM12b job format -* API: DataGrabber and SelectFiles use human (or natural) sort now - -* FIX: Several fixes related to Camino interfaces: - - ProcStreamlines would ignore many arguments silently (target, waypoint, exclusion ROIS, etc.) - - DTLUTGen would silently round the "step", "snr" and "trace" parameters to integers - - PicoPDFs would not accept more than one lookup table - - PicoPDFs default pdf did not correspond to Camino default - - Track input model names were outdated (and would generate an error) - - Track numpds parameter could not be set for deterministic tractography - - FA created output files with erroneous extension -* FIX: Deals properly with 3d files in SPM Realign -* FIX: SPM with MCR fixed -* FIX: Cleaned up input and output spec metadata -* FIX: example openfmri script now makes the contrast spec a hashed input -* FIX: FILMGLS compatibility with FSL 5.0.5 -* FIX: Freesurfer recon-all resume now avoids setting inputs -* FIX: File removal from node respects file associations img/hdr/mat, BRIK/HEAD - -Release 0.8.0 (May 8, 2013) -=========================== - -* ENH: New interfaces: nipy.Trim, fsl.GLM, fsl.SigLoss, spm.VBMSegment, fsl.InvWarp, - dipy.TensorMode -* ENH: Allow control over terminal output for commandline interfaces -* ENH: Added preliminary support for generating Python code from Workflows. -* ENH: New workflows for dMRI and fMRI pre-processing: added motion artifact correction - with rotation of the B-matrix, and susceptibility correction for EPI imaging using - fieldmaps. Updated eddy_correct pipeline to support both dMRI and fMRI, and new parameters. -* ENH: Minor improvements to FSL's FUGUE and FLIRT interfaces -* ENH: Added optional dilation of parcels in cmtk.Parcellate -* ENH: Interpolation mode added to afni.Resample -* ENH: Function interface can accept a list of strings containing import statements - that allow external functions to run without their imports defined in the - function body -* ENH: Allow node configurations to override master configuration - -* FIX: SpecifyModel works with 3D files correctly now. - -Release 0.7.0 (Dec 18, 2012) -============================ - -* ENH: Add basic support for LSF plugin. -* ENH: New interfaces: ICC, Meshfix, ants.Register, C3dAffineTool, ants.JacobianDeterminant, - afni.AutoTcorrelate, DcmStack -* ENH: New workflows: ants template building (both using 'ANTS' and the new 'antsRegistration') -* ENH: New examples: how to use ANTS template building workflows (smri_ants_build_tmeplate), - how to set SGE specific options (smri_ants_build_template_new) -* ENH: added no_flatten option to Merge -* ENH: added versioning option and checking to traits -* ENH: added deprecation metadata to traits -* ENH: Slicer interfaces were updated to version 4.1 - -Release 0.6.0 (Jun 30, 2012) -============================ - -* API: display variable no longer encoded as inputs in commandline interfaces - -* ENH: input hash not modified when environment DISPLAY is changed -* ENH: support for 3d files for TSNR calculation -* ENH: Preliminary support for graph submission with SGE, PBS and Soma Workflow -* ENH: New interfaces: MySQLSink, nipy.Similarity, WatershedBEM, MRIsSmooth, - NetworkBasedStatistic, Atropos, N4BiasFieldCorrection, ApplyTransforms, - fs.MakeAverageSubject, epidewarp.fsl, WarpTimeSeriesImageMultiTransform, - AVScale, mri_ms_LDA -* ENH: simple interfaces for spm - -* FIX: CompCor component calculation was erroneous -* FIX: filename generation for AFNI and PRELUDE -* FIX: improved slicer module autogeneration -* FIX: added missing options for BBRegsiter -* FIX: functionality of remove_unnecessary_ouputs cleaned up -* FIX: local hash check works with appropriate inputs -* FIX: Captures all stdout from commandline programs -* FIX: Afni outputs should inherit from TraitedSpec - -Release 0.5.3 (Mar 23, 2012) -============================ - -* FIX: SPM model generation when output units is in scans - -Release 0.5.2 (Mar 14, 2012) -============================ - -* API: Node now allows specifying node level configuration for SGE/PBS clusters -* API: Logging to file is disabled by default -* API: New location of log file -> .nipype/nipype.cfg - -* ENH: Changing logging options via config works for distributed processing - -* FIX: Unittests on debian (logging and ipython) - -Release 0.5 (Mar 10, 2012) -========================== - -* API: FSL defaults to Nifti when OUTPUTTYPE environment variable not found -* API: By default inputs are removed from Node working directory -* API: InterfaceResult class is now versioned and stores class type not instance -* API: Added FIRST interface -* API: Added max_jobs paramter to plugin_args. limits the number of jobs - executing at any given point in time -* API: crashdump_dir is now a config execution option -* API: new config execution options for controlling hash checking, execution and - logging behavior when running in distributed mode. -* API: Node/MapNode has new attribute that allows it to run on master thread. -* API: IPython plugin now invokes IPython 0.11 or greater -* API: Canned workflows are now all under a different package structure -* API: SpecifyModel event_info renamed to event_files -* API: DataGrabber is always being rerun (unless overwrite is set to False on - Node level) -* API: "stop_on_first_rerun" does not stop for DataGrabber (unless overwrite is - set to True on Node level) -* API: Output prefix can be set for spm nodes (SliceTiming, Realign, Coregister, - Normalize, Smooth) - -* ENH: Added fsl resting state workflow based on behzadi 2007 CompCorr method. -* ENH: TSNR node produces mean and std-dev maps; allows polynomial detrending -* ENH: IdentityNodes are removed prior to execution -* ENH: Added Michael Notter's beginner's guide -* ENH: Added engine support for status callback functions -* ENH: SPM create warped node -* ENH: All underlying interfaces (including python ones) are now optional -* ENH: Added imperative programming option with Nodes and caching -* ENH: Added debug mode to configuration -* ENH: Results can be stored and loaded without traits exceptions -* ENH: Added concurrent log handler for distributed writing to log file -* ENH: Reporting can be turned off using config -* ENH: Added stats files to FreeSurferOutput -* ENH: Support for Condor through qsub emulation -* ENH: IdentityNode with iterable expansion takes place after remaining Identity - Node removal -* ENH: Crashfile display script added -* ENH: Added FmriRealign4d node wrapped from nipy -* ENH: Added TBSS workflows and examples -* ENH: Support for openfmri data processing -* ENH: Package version check - -* FIX: Fixed spm preproc workflow to cater to multiple functional runs -* FIX: Workflow outputs displays nodes with empty outputs -* FIX: SUSAN workflow works without usans -* FIX: SGE fixed for reading custom templates -* FIX: warping in SPM realign, Dartel and interpolation parameters -* FIX: Fixed voxel size parameter in freesurfer mri_convert -* FIX: 4D images in spm coregister -* FIX: Works around matlab tty bug -* FIX: Overwriting connection raises exception -* FIX: Outputs are loaded from results and not stored in memory for during - distributed operation -* FIX: SPM threshold uses SPM.mat name and improved error detection -* FIX: Removing directory contents works even when a node has no outputs -* FIX: DARTEL workflows will run only when SPM 8 is available -* FIX: SPM Normalize estimate field fixed -* FIX: hashmethod argument now used for calculating hash of old file -* FIX: Modelgen now allows FSL style event files - -Release 0.4.1 (Jun 16, 2011) -============================ - -* Minor bugfixes - -Release 0.4 (Jun 11, 2011) -========================== - -* API: Timestamp hashing does not use ctime anymore. Please update your hashes by - running workflows with updatehash=True option - NOTE: THIS IS THE DEFAULT CONFIG NOW, so unless you updatehash, workflows will - rerun -* API: Workflow run function no longer supports (inseries, createdirsonly). - Functions used in connect string must be pickleable -* API: SPM EstimateContrast: ignore_derivs replaced by use_derivs -* API: All interfaces: added new config option ignore_exception -* API: SpecifModel no longer supports (concatenate_runs, output_specs). high_pass_filter - cutoff is mandatory (even if its set to np.inf). Additional interfaces - SpecifySPMModel and SpecifySparseModel support other types of data. -* API: fsl.DTIFit input "save" is now called "save_tensor" -* API: All inputs of IdentityInterfaces are mandatory by default. You can turn - this off by specifying mandatory_inputs=False to the constructor. -* API: fsl FILMGLS input "autocorr_estimate" is now called "autocorr_estimate_only" -* API: fsl ContrastMgr now requires access to specific files (no longer accepts - the result directory) -* API: freesurfer.GLMFit input "surf" is now a boolean with three corresponding - inputs -- subject_id, hemi, and surf_geo - -* ENH: All commandline interfaces display stdout and stderr -* ENH: All interfaces raise exceptions on error with an option to suppress -* ENH: Supports a plugin interface for execution (current support for multiprocessing, - IPython, SGE, PBS) -* ENH: MapNode runs in parallel under IPython, SGE, MultiProc, PBS -* ENH: Optionally allows keeping only required outputs -* ENH: New interface: utility.Rename to change the name of files, optionally - using python string-formatting with inputs or regular expressions matching -* ENH: New interface: freesurfer.ApplyMask (mri_mask) -* ENH: New FSL interface -- SwapDimensions (fslswapdim) -* ENH: Sparse models allow regressor scaling and temporal derivatives -* ENH: Added support for the component parts of FSL's TBSS workflow (TBSSSkeleton - and DistanceMap) -* ENH: dcm2nii interface exposes bvals, bvecs, reoriented and cropped images -* ENH: Added several higher-level interfaces to the fslmaths command: - - ChangeDataType, Threshold, MeanImage, IsotropicSmooth, ApplyMask, TemporalFilter - DilateImage, ErodeImage, SpatialFilter, UnaryMaths, BinaryMaths, MultiImageMaths -* ENH: added support for networx 1.4 and improved iterable expansion -* ENH: Replaced BEDPOSTX and EddyCurrent with nipype pipelines -* ENH: Ability to create a hierarchical dot file -* ENH: Improved debugging information for rerunning nodes -* ENH: Added 'stop_on_first_rerun' option -* ENH: Added support for Camino -* ENH: Added support for Camino2Trackvis -* ENH: Added support for Connectome Viewer - -* BF: dcm2nii interface handles gzipped files correctly -* BF: FNIRT generates proper outputs -* BF: fsl.DTIFit now properly collects tensor volume -* BF: updatehash now removes old result hash file - -Release 0.3.4 (Jan 12, 2011) -============================ - -* API: hash values for float use a string conversion up to the 10th decimal place. -* API: Iterables in output path will always be generated as _var1_val1_var2_val2 pairs - -* ENH: Added support to nipy: GLM fit, contrast estimation and calculating mask from EPI -* ENH: Added support for manipulating surface files in Freesurfer: - - projecting volume images onto the surface - - smoothing along the surface - - transforming a surface image from one subject to another - - using tksurfer to save pictures of the surface -* ENH: Added support for flash processing using FreeSurfer -* ENH: Added support for flirt matrix in BBRegister -* ENH: Added support for FSL convert_xfm -* ENH: hashes can be updated again without rerunning all nodes. -* ENH: Added multiple regression design for FSL -* ENH: Added SPM based Analyze to Nifti converter -* ENH: Added increased support for PyXNAT -* ENH: Added support for MCR-based binary version of SPM -* ENH: Added SPM node for calculating various threshold statistics -* ENH: Added distance and dissimilarity measurements - -* BF: Diffusion toolkit gets installed -* BF: Changed FNIRT interface to accept flexible lists (rather than 4-tuples) - on all options specific to different subsampling levels - -Release 0.3.3 (Sep 16, 2010) -============================ - -* API: subject_id in ModelSpec is now deprecated -* API: spm.Threshold - - does not need mask, beta, RPV anymore - - takes only one image (stat_image - mind the name change) - - works with SPM2 SPM.mat - - returns additional map - pre topological FDR - -* ENH: Added support for Diffusion toolkit -* ENH: Added support for FSL slicer and overlay -* ENH: Added support for dcm2nii - -* BF: DataSink properly handles lists of lists now -* BF: DataGrabber has option for raising Exception on getting empty lists -* BF: Traits logic for 'requires' metadata -* BF: allows workflows to be relocatable -* BF: nested workflows with connections don't raise connection not found error -* BF: multiple workflows with identical nodenames and iterables do not create nestsed workflows - -Release 0.3.2 (Aug 03, 2010) -============================ - -Enhancements ------------- - - - all outputs from nodes are now pickled as part of workflow processing - - added git developer docs - -Bugs fixed ----------- - -* FreeSurfer - - - Fixed bugs in SegStats doctest - -Release 0.3.1 (Jul 29, 2010) -============================ - -Bugs fixed ----------- - -* FreeSurfer - - - Fixed bugs in glmfit and concatenate - - Added group t-test to freesurfer tutorial - -Release 0.3 (Jul 27, 2010) -========================== - -Incompatible changes --------------------- - -* Complete redesign of the Interface class - heavy use of Traits. - -* Changes in the engine API - added Workflow and MapNode. Compulsory name argument. - -Features added --------------- - -* General: - - - Type checking of inputs and outputs using Traits from ETS_. - - Support for nested workflows. - - Preliminary Slicer and AFNI support. - - New flexible DataGrabber node. - - AtlasPick and Threshold nodes. - - Preliminary support for XNAT. - - Doubled number of the tutorials. - -* FSL: - - - Added DTI processing nodes (note that TBSS nodes are still experimental). - - Recreated FEAT workflow. - -* SPM: - - - Added New Segment and many other nodes. - - Redesigned second level analysis. diff --git a/doc/users/debug.rst b/doc/users/debug.rst index 91aa3b6f2f..303df9f82a 100644 --- a/doc/users/debug.rst +++ b/doc/users/debug.rst @@ -42,6 +42,9 @@ performance issues. #. All Nipype crashfiles can be inspected with the `nipype_display_crash` utility. +#. The `nipype_crash_search` command allows you to search for regular expressions +in the tracebacks of the Nipype crashfiles within a log folder. + #. Nipype determines the hash of the input state of a node. If any input contains strings that represent files on the system path, the hash evaluation mechanism will determine the timestamp or content hash of each of those