From ee9fb50821b7fdde3425acd002b650f0b94b7903 Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Tue, 24 Jan 2017 11:40:29 -0500 Subject: [PATCH 1/8] WIP Update ReconAll interface for v6 --- nipype/interfaces/freesurfer/preprocess.py | 106 +++++++++++---------- 1 file changed, 55 insertions(+), 51 deletions(-) diff --git a/nipype/interfaces/freesurfer/preprocess.py b/nipype/interfaces/freesurfer/preprocess.py index ecced01676..eebc00899e 100644 --- a/nipype/interfaces/freesurfer/preprocess.py +++ b/nipype/interfaces/freesurfer/preprocess.py @@ -659,52 +659,48 @@ class ReconAll(CommandLine): _steps = [ # autorecon1 ('motioncor', ['mri/rawavg.mgz', 'mri/orig.mgz']), - ('talairach', ['mri/transforms/talairach.auto.xfm', - 'mri/transforms/talairach.xfm']), + ('talairach', ['mri/orig_nu.mgz', + 'mri/transforms/talairach.auto.xfm', + 'mri/transforms/talairach.xfm', + # 'mri/transforms/talairach_avi.log', + ]), ('nuintensitycor', ['mri/nu.mgz']), ('normalization', ['mri/T1.mgz']), - ('skullstrip', - ['mri/brainmask.auto.mgz', - 'mri/brainmask.mgz']), + ('skullstrip', ['mri/talairach_with_skull.lta', + 'mri/brainmask.auto.mgz', + 'mri/brainmask.mgz']), # autorecon2 ('gcareg', ['mri/transforms/talairach.lta']), ('canorm', ['mri/norm.mgz']), ('careg', ['mri/transforms/talairach.m3z']), - ('careginv', ['mri/transforms/talairach.m3z.inv.x.mgz', - 'mri/transforms/talairach.m3z.inv.y.mgz', - 'mri/transforms/talairach.m3z.inv.z.mgz']), - ('rmneck', ['mri/nu_noneck.mgz']), - ('skull-lta', ['mri/transforms/talairach_with_skull_2.lta']), - ('calabel', - ['mri/aseg.auto_noCCseg.mgz', 'mri/aseg.auto.mgz', 'mri/aseg.mgz']), + ('calabel', ['mri/aseg.auto_noCCseg.mgz', + 'mri/aseg.auto.mgz', + 'mri/aseg.mgz']), ('normalization2', ['mri/brain.mgz']), ('maskbfs', ['mri/brain.finalsurfs.mgz']), - ('segmentation', ['mri/wm.asegedit.mgz', 'mri/wm.mgz']), - ('fill', ['mri/filled.mgz']), + ('segmentation', ['mri/wm.seg.mgz', + 'mri/wm.asegedit.mgz', + 'mri/wm.mgz']), + ('fill', ['mri/filled.mgz', + # 'scripts/ponscc.cut.log', + ]), ('tessellate', ['surf/lh.orig.nofix', 'surf/rh.orig.nofix']), ('smooth1', ['surf/lh.smoothwm.nofix', 'surf/rh.smoothwm.nofix']), ('inflate1', ['surf/lh.inflated.nofix', 'surf/rh.inflated.nofix']), ('qsphere', ['surf/lh.qsphere.nofix', 'surf/rh.qsphere.nofix']), ('fix', ['surf/lh.orig', 'surf/rh.orig']), - ('white', - ['surf/lh.white', - 'surf/rh.white', - 'surf/lh.curv', - 'surf/rh.curv', - 'surf/lh.area', - 'surf/rh.area', - 'label/lh.cortex.label', - 'label/rh.cortex.label']), + ('white', ['surf/lh.white.preaparc', 'surf/rh.white.preaparc', + 'surf/lh.curv', 'surf/rh.curv', + 'surf/lh.area', 'surf/rh.area', + 'label/lh.cortex.label', 'label/rh.cortex.label']), ('smooth2', ['surf/lh.smoothwm', 'surf/rh.smoothwm']), - ('inflate2', - ['surf/lh.inflated', - 'surf/rh.inflated', - 'surf/lh.sulc', - 'surf/rh.sulc', - 'surf/lh.inflated.H', - 'surf/rh.inflated.H', - 'surf/lh.inflated.K', - 'surf/rh.inflated.K']), + ('inflate2', ['surf/lh.inflated', 'surf/rh.inflated', + 'surf/lh.sulc', 'surf/rh.sulc']), + ('curvHK', ['surf/lh.white.H', 'surf/rh.white.H', + 'surf/lh.white.K', 'surf/rh.white.K', + 'surf/lh.inflated.H', 'surf/rh.inflated.H', + 'surf/lh.inflated.K', 'surf/rh.inflated.K']), + ('curvstats', ['stats/lh.curv.stats', 'stats/rh.curv.stats']), # autorecon3 ('sphere', ['surf/lh.sphere', 'surf/rh.sphere']), ('surfreg', ['surf/lh.sphere.reg', 'surf/rh.sphere.reg']), @@ -712,29 +708,37 @@ class ReconAll(CommandLine): 'surf/rh.jacobian_white']), ('avgcurv', ['surf/lh.avg_curv', 'surf/rh.avg_curv']), ('cortparc', ['label/lh.aparc.annot', 'label/rh.aparc.annot']), - ('pial', - ['surf/lh.pial', - 'surf/rh.pial', - 'surf/lh.curv.pial', - 'surf/rh.curv.pial', - 'surf/lh.area.pial', - 'surf/rh.area.pial', - 'surf/lh.thickness', - 'surf/rh.thickness']), - ('cortparc2', ['label/lh.aparc.a2009s.annot', - 'label/rh.aparc.a2009s.annot']), - ('parcstats2', - ['stats/lh.aparc.a2009s.stats', - 'stats/rh.aparc.a2009s.stats', - 'stats/aparc.annot.a2009s.ctab']), + ('pial', ['surf/lh.pial', 'surf/rh.pial', + 'surf/lh.curv.pial', 'surf/rh.curv.pial', + 'surf/lh.area.pial', 'surf/rh.area.pial', + 'surf/lh.thickness', 'surf/rh.thickness']), + # TODO: Optional -T2pial / -FLAIRpial ('cortribbon', ['mri/lh.ribbon.mgz', 'mri/rh.ribbon.mgz', 'mri/ribbon.mgz']), + ('parcstats', ['stats/lh.aparc.astats', 'stats/rh.aparc.stats', + 'stats/aparc.annot.ctab']), + ('cortparc2', ['label/lh.aparc.a2009s.annot', + 'label/rh.aparc.a2009s.annot']), + ('parcstats2', ['stats/lh.aparc.a2009s.stats', + 'stats/rh.aparc.a2009s.stats', + 'stats/aparc.annot.a2009s.ctab']), + ('cortparc3', ['label/lh.aparc.DKTatlas.annot', + 'label/rh.aparc.DKTatlas.annot']), + ('parcstats3', ['stats/lh.aparc.DKTatlas.stats', + 'stats/rh.aparc.DKTatlas.stats', + 'stats/aparc.annot.DKTatlas.ctab']), + ('pctsurfcon', ['surf/lh.w-g.pct.mgh', 'surf/rh.w-g.pct.mgh']), + ('hyporelabel', ['mri/aseg.presurf.hypos.mgz']), + ('aparc2aseg', ['mri/aparc+aseg.mgz', + 'mri/aparc.a2009s+aseg.mgz', + 'mri/aparc.DKTatlas+aseg.mgz']), + ('apas2aseg', ['mri/aseg.mgz']), # XXX: Will not run because of calabel ('segstats', ['stats/aseg.stats']), - ('aparc2aseg', ['mri/aparc+aseg.mgz', 'mri/aparc.a2009s+aseg.mgz']), ('wmparc', ['mri/wmparc.mgz', 'stats/wmparc.stats']), - ('balabels', ['BA.ctab', 'BA.thresh.ctab']), - ('label-exvivo-ec', ['label/lh.entorhinal_exvivo.label', - 'label/rh.entorhinal_exvivo.label'])] + ('balabels', ['BA.ctab', 'BA.thresh.ctab', + 'label/lh.entorhinal_exvivo.label', + 'label/rh.entorhinal_exvivo.label']), + ] def _gen_subjects_dir(self): return os.getcwd() From 75cae9f457ef45a00050feeb2631f79c2848648a Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Fri, 27 Jan 2017 17:05:17 -0500 Subject: [PATCH 2/8] Prevent resume flags from clobbering explicit args --- nipype/interfaces/freesurfer/preprocess.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/nipype/interfaces/freesurfer/preprocess.py b/nipype/interfaces/freesurfer/preprocess.py index eebc00899e..c8564e5bef 100644 --- a/nipype/interfaces/freesurfer/preprocess.py +++ b/nipype/interfaces/freesurfer/preprocess.py @@ -800,16 +800,21 @@ def cmdline(self): directive = 'all' for idx, step in enumerate(self._steps): step, outfiles = step + flag = '-{}'.format(step) + noflag = '-no{}'.format(step) + if flag in cmd or noflag in cmd: + continue + if all([os.path.exists(os.path.join(subjects_dir, self.inputs.subject_id, f)) for f in outfiles]): - flags.append('-no%s' % step) + flags.append(noflag) if idx > 4: directive = 'autorecon2' elif idx > 23: directive = 'autorecon3' else: - flags.append('-%s' % step) + flags.append(flag) cmd = cmd.replace(' -%s ' % self.inputs.directive, ' -%s ' % directive) cmd += ' ' + ' '.join(flags) iflogger.info('resume recon-all : %s' % cmd) From 141267f8c4770d9570c027b78c4bf84be4fe911e Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Mon, 30 Jan 2017 12:29:12 -0500 Subject: [PATCH 3/8] Add optional dependencies to ReconAll._steps --- nipype/interfaces/freesurfer/preprocess.py | 95 +++++++++++----------- nipype/utils/filemanip.py | 13 +++ 2 files changed, 60 insertions(+), 48 deletions(-) diff --git a/nipype/interfaces/freesurfer/preprocess.py b/nipype/interfaces/freesurfer/preprocess.py index c8564e5bef..29eb42fe0b 100644 --- a/nipype/interfaces/freesurfer/preprocess.py +++ b/nipype/interfaces/freesurfer/preprocess.py @@ -22,7 +22,7 @@ from nibabel import load from ... import logging -from ...utils.filemanip import fname_presuffix +from ...utils.filemanip import fname_presuffix, check_depends from ..io import FreeSurferSource from ..base import (TraitedSpec, File, traits, Directory, InputMultiPath, @@ -658,86 +658,85 @@ class ReconAll(CommandLine): _steps = [ # autorecon1 - ('motioncor', ['mri/rawavg.mgz', 'mri/orig.mgz']), + ('motioncor', ['mri/rawavg.mgz', 'mri/orig.mgz'], []), ('talairach', ['mri/orig_nu.mgz', 'mri/transforms/talairach.auto.xfm', 'mri/transforms/talairach.xfm', # 'mri/transforms/talairach_avi.log', - ]), - ('nuintensitycor', ['mri/nu.mgz']), - ('normalization', ['mri/T1.mgz']), + ], []), + ('nuintensitycor', ['mri/nu.mgz'], []), + ('normalization', ['mri/T1.mgz'], []), ('skullstrip', ['mri/talairach_with_skull.lta', 'mri/brainmask.auto.mgz', - 'mri/brainmask.mgz']), + 'mri/brainmask.mgz'], []), # autorecon2 - ('gcareg', ['mri/transforms/talairach.lta']), - ('canorm', ['mri/norm.mgz']), - ('careg', ['mri/transforms/talairach.m3z']), + ('gcareg', ['mri/transforms/talairach.lta'], []), + ('canorm', ['mri/norm.mgz'], []), + ('careg', ['mri/transforms/talairach.m3z'], []), ('calabel', ['mri/aseg.auto_noCCseg.mgz', 'mri/aseg.auto.mgz', - 'mri/aseg.mgz']), - ('normalization2', ['mri/brain.mgz']), - ('maskbfs', ['mri/brain.finalsurfs.mgz']), + 'mri/aseg.mgz'], []), + ('normalization2', ['mri/brain.mgz'], []), + ('maskbfs', ['mri/brain.finalsurfs.mgz'], []), ('segmentation', ['mri/wm.seg.mgz', 'mri/wm.asegedit.mgz', - 'mri/wm.mgz']), + 'mri/wm.mgz'], []), ('fill', ['mri/filled.mgz', # 'scripts/ponscc.cut.log', - ]), - ('tessellate', ['surf/lh.orig.nofix', 'surf/rh.orig.nofix']), - ('smooth1', ['surf/lh.smoothwm.nofix', 'surf/rh.smoothwm.nofix']), - ('inflate1', ['surf/lh.inflated.nofix', 'surf/rh.inflated.nofix']), - ('qsphere', ['surf/lh.qsphere.nofix', 'surf/rh.qsphere.nofix']), - ('fix', ['surf/lh.orig', 'surf/rh.orig']), + ], []), + ('tessellate', ['surf/lh.orig.nofix', 'surf/rh.orig.nofix'], []), + ('smooth1', ['surf/lh.smoothwm.nofix', 'surf/rh.smoothwm.nofix'], []), + ('inflate1', ['surf/lh.inflated.nofix', 'surf/rh.inflated.nofix'], []), + ('qsphere', ['surf/lh.qsphere.nofix', 'surf/rh.qsphere.nofix'], []), + ('fix', ['surf/lh.orig', 'surf/rh.orig'], []), ('white', ['surf/lh.white.preaparc', 'surf/rh.white.preaparc', 'surf/lh.curv', 'surf/rh.curv', 'surf/lh.area', 'surf/rh.area', - 'label/lh.cortex.label', 'label/rh.cortex.label']), - ('smooth2', ['surf/lh.smoothwm', 'surf/rh.smoothwm']), + 'label/lh.cortex.label', 'label/rh.cortex.label'], []), + ('smooth2', ['surf/lh.smoothwm', 'surf/rh.smoothwm'], []), ('inflate2', ['surf/lh.inflated', 'surf/rh.inflated', - 'surf/lh.sulc', 'surf/rh.sulc']), + 'surf/lh.sulc', 'surf/rh.sulc'], []), ('curvHK', ['surf/lh.white.H', 'surf/rh.white.H', 'surf/lh.white.K', 'surf/rh.white.K', 'surf/lh.inflated.H', 'surf/rh.inflated.H', - 'surf/lh.inflated.K', 'surf/rh.inflated.K']), - ('curvstats', ['stats/lh.curv.stats', 'stats/rh.curv.stats']), + 'surf/lh.inflated.K', 'surf/rh.inflated.K'], []), + ('curvstats', ['stats/lh.curv.stats', 'stats/rh.curv.stats'], []), # autorecon3 - ('sphere', ['surf/lh.sphere', 'surf/rh.sphere']), - ('surfreg', ['surf/lh.sphere.reg', 'surf/rh.sphere.reg']), + ('sphere', ['surf/lh.sphere', 'surf/rh.sphere'], []), + ('surfreg', ['surf/lh.sphere.reg', 'surf/rh.sphere.reg'], []), ('jacobian_white', ['surf/lh.jacobian_white', - 'surf/rh.jacobian_white']), - ('avgcurv', ['surf/lh.avg_curv', 'surf/rh.avg_curv']), - ('cortparc', ['label/lh.aparc.annot', 'label/rh.aparc.annot']), + 'surf/rh.jacobian_white'], []), + ('avgcurv', ['surf/lh.avg_curv', 'surf/rh.avg_curv'], []), + ('cortparc', ['label/lh.aparc.annot', 'label/rh.aparc.annot'], []), ('pial', ['surf/lh.pial', 'surf/rh.pial', 'surf/lh.curv.pial', 'surf/rh.curv.pial', 'surf/lh.area.pial', 'surf/rh.area.pial', - 'surf/lh.thickness', 'surf/rh.thickness']), - # TODO: Optional -T2pial / -FLAIRpial + 'surf/lh.thickness', 'surf/rh.thickness'], []), ('cortribbon', ['mri/lh.ribbon.mgz', 'mri/rh.ribbon.mgz', - 'mri/ribbon.mgz']), + 'mri/ribbon.mgz'], []), ('parcstats', ['stats/lh.aparc.astats', 'stats/rh.aparc.stats', - 'stats/aparc.annot.ctab']), + 'stats/aparc.annot.ctab'], []), ('cortparc2', ['label/lh.aparc.a2009s.annot', - 'label/rh.aparc.a2009s.annot']), + 'label/rh.aparc.a2009s.annot'], []), ('parcstats2', ['stats/lh.aparc.a2009s.stats', 'stats/rh.aparc.a2009s.stats', - 'stats/aparc.annot.a2009s.ctab']), + 'stats/aparc.annot.a2009s.ctab'], []), ('cortparc3', ['label/lh.aparc.DKTatlas.annot', - 'label/rh.aparc.DKTatlas.annot']), + 'label/rh.aparc.DKTatlas.annot'], []), ('parcstats3', ['stats/lh.aparc.DKTatlas.stats', 'stats/rh.aparc.DKTatlas.stats', - 'stats/aparc.annot.DKTatlas.ctab']), - ('pctsurfcon', ['surf/lh.w-g.pct.mgh', 'surf/rh.w-g.pct.mgh']), - ('hyporelabel', ['mri/aseg.presurf.hypos.mgz']), + 'stats/aparc.annot.DKTatlas.ctab'], []), + ('pctsurfcon', ['surf/lh.w-g.pct.mgh', 'surf/rh.w-g.pct.mgh'], []), + ('hyporelabel', ['mri/aseg.presurf.hypos.mgz'], []), ('aparc2aseg', ['mri/aparc+aseg.mgz', 'mri/aparc.a2009s+aseg.mgz', - 'mri/aparc.DKTatlas+aseg.mgz']), - ('apas2aseg', ['mri/aseg.mgz']), # XXX: Will not run because of calabel - ('segstats', ['stats/aseg.stats']), - ('wmparc', ['mri/wmparc.mgz', 'stats/wmparc.stats']), + 'mri/aparc.DKTatlas+aseg.mgz'], []), + ('apas2aseg', ['mri/aseg.mgz'], ['mri/aparc+aseg.mgz']), + ('segstats', ['stats/aseg.stats'], []), + ('wmparc', ['mri/wmparc.mgz', 'stats/wmparc.stats'], []), ('balabels', ['BA.ctab', 'BA.thresh.ctab', 'label/lh.entorhinal_exvivo.label', - 'label/rh.entorhinal_exvivo.label']), + 'label/rh.entorhinal_exvivo.label'], []), ] def _gen_subjects_dir(self): @@ -799,15 +798,15 @@ def cmdline(self): flags = [] directive = 'all' for idx, step in enumerate(self._steps): - step, outfiles = step + step, outfiles, infiles = step flag = '-{}'.format(step) noflag = '-no{}'.format(step) if flag in cmd or noflag in cmd: continue - if all([os.path.exists(os.path.join(subjects_dir, - self.inputs.subject_id, f)) for - f in outfiles]): + subj_dir = os.path.join(subjects_dir, self.inputs.subject_id) + if check_depends([os.path.join(subj_dir, f) for f in outfiles], + [os.path.join(subj_dir, f) for f in infiles]): flags.append(noflag) if idx > 4: directive = 'autorecon2' diff --git a/nipype/utils/filemanip.py b/nipype/utils/filemanip.py index 3f7f7462f9..697d92b2e7 100644 --- a/nipype/utils/filemanip.py +++ b/nipype/utils/filemanip.py @@ -447,6 +447,19 @@ def list_to_filename(filelist): else: return filelist[0] + +def check_depends(targets, dependencies): + """Return true if all targets exist and are newer than all dependencies. + + An OSError will be raised if there are missing dependencies. + """ + tgts = filename_to_list(targets) + deps = filename_to_list(dependencies) + return all(map(os.path.exists, tgts)) and \ + min(map(os.path.getmtime, tgts)) > \ + max(map(os.path.getmtime, deps), default=0) + + def save_json(filename, data): """Save data to a json file From 8e914f32111f6b6fe1512ef11f2c90af71110122 Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Mon, 30 Jan 2017 12:57:08 -0500 Subject: [PATCH 4/8] Remove faulty directive overrides Assuming any directive maps to '-all' with all previous steps completed is incorrect. Further, the directive update to 'autorecon2' precludes the completion of 'autorecon3', which 'all' includes. Taking the existing directive and removing completed steps is a more conservative approach, with less chance of unexpected behavior. --- nipype/interfaces/freesurfer/preprocess.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/nipype/interfaces/freesurfer/preprocess.py b/nipype/interfaces/freesurfer/preprocess.py index 29eb42fe0b..a1853f1b1e 100644 --- a/nipype/interfaces/freesurfer/preprocess.py +++ b/nipype/interfaces/freesurfer/preprocess.py @@ -793,10 +793,8 @@ def cmdline(self): subjects_dir = self.inputs.subjects_dir if not isdefined(subjects_dir): subjects_dir = self._gen_subjects_dir() - # cmd = cmd.replace(' -all ', ' -make all ') - iflogger.info('Overriding recon-all directive') + flags = [] - directive = 'all' for idx, step in enumerate(self._steps): step, outfiles, infiles = step flag = '-{}'.format(step) @@ -808,14 +806,8 @@ def cmdline(self): if check_depends([os.path.join(subj_dir, f) for f in outfiles], [os.path.join(subj_dir, f) for f in infiles]): flags.append(noflag) - if idx > 4: - directive = 'autorecon2' - elif idx > 23: - directive = 'autorecon3' - else: - flags.append(flag) - cmd = cmd.replace(' -%s ' % self.inputs.directive, ' -%s ' % directive) cmd += ' ' + ' '.join(flags) + iflogger.info('resume recon-all : %s' % cmd) return cmd From b8d2b08537ff608d7d3daca3bf883895838aa7ee Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Tue, 31 Jan 2017 20:43:44 -0500 Subject: [PATCH 5/8] Re-add v5.3 steps --- nipype/interfaces/freesurfer/preprocess.py | 237 ++++++++++++++------- 1 file changed, 165 insertions(+), 72 deletions(-) diff --git a/nipype/interfaces/freesurfer/preprocess.py b/nipype/interfaces/freesurfer/preprocess.py index a1853f1b1e..73d8b3637c 100644 --- a/nipype/interfaces/freesurfer/preprocess.py +++ b/nipype/interfaces/freesurfer/preprocess.py @@ -21,7 +21,7 @@ import numpy as np from nibabel import load -from ... import logging +from ... import logging, LooseVersion from ...utils.filemanip import fname_presuffix, check_depends from ..io import FreeSurferSource from ..base import (TraitedSpec, File, traits, @@ -30,12 +30,20 @@ CommandLineInputSpec, isdefined) from .base import (FSCommand, FSTraitedSpec, FSTraitedSpecOpenMP, - FSCommandOpenMP) + FSCommandOpenMP, Info) from .utils import copy2subjdir __docformat__ = 'restructuredtext' iflogger = logging.getLogger('interface') +FSVersion = "0" +_ver = Info.version() +if _ver: + if 'dev' in _ver: + FSVersion = _ver.rstrip().split('-')[-1] + '.dev' + else: + FSVersion = _ver.rstrip().split('-v')[-1] + class ParseDICOMDirInputSpec(FSTraitedSpec): dicom_dir = Directory(exists=True, argstr='--d %s', mandatory=True, @@ -656,8 +664,19 @@ class ReconAll(CommandLine): output_spec = ReconAllOutputSpec _can_resume = True - _steps = [ - # autorecon1 + # Steps are based off of the recon-all tables [0,1] describing, inputs, + # commands, and outputs of each step of the recon-all process, + # controlled by flags. + # + # Each step is a 3-tuple containing (flag, [outputs], [inputs]) + # A step is considered complete if all of its outputs exist and are newer + # than the inputs. An empty input list indicates input mtimes will not + # be checked. This may need updating, if users are working with manually + # edited files. + # + # [0] https://surfer.nmr.mgh.harvard.edu/fswiki/ReconAllTableStableV5.3 + # [1] https://surfer.nmr.mgh.harvard.edu/fswiki/ReconAllTableStableV6.0 + _autorecon1_steps = [ ('motioncor', ['mri/rawavg.mgz', 'mri/orig.mgz'], []), ('talairach', ['mri/orig_nu.mgz', 'mri/transforms/talairach.auto.xfm', @@ -669,75 +688,149 @@ class ReconAll(CommandLine): ('skullstrip', ['mri/talairach_with_skull.lta', 'mri/brainmask.auto.mgz', 'mri/brainmask.mgz'], []), - # autorecon2 - ('gcareg', ['mri/transforms/talairach.lta'], []), - ('canorm', ['mri/norm.mgz'], []), - ('careg', ['mri/transforms/talairach.m3z'], []), - ('calabel', ['mri/aseg.auto_noCCseg.mgz', - 'mri/aseg.auto.mgz', - 'mri/aseg.mgz'], []), - ('normalization2', ['mri/brain.mgz'], []), - ('maskbfs', ['mri/brain.finalsurfs.mgz'], []), - ('segmentation', ['mri/wm.seg.mgz', - 'mri/wm.asegedit.mgz', - 'mri/wm.mgz'], []), - ('fill', ['mri/filled.mgz', - # 'scripts/ponscc.cut.log', - ], []), - ('tessellate', ['surf/lh.orig.nofix', 'surf/rh.orig.nofix'], []), - ('smooth1', ['surf/lh.smoothwm.nofix', 'surf/rh.smoothwm.nofix'], []), - ('inflate1', ['surf/lh.inflated.nofix', 'surf/rh.inflated.nofix'], []), - ('qsphere', ['surf/lh.qsphere.nofix', 'surf/rh.qsphere.nofix'], []), - ('fix', ['surf/lh.orig', 'surf/rh.orig'], []), - ('white', ['surf/lh.white.preaparc', 'surf/rh.white.preaparc', - 'surf/lh.curv', 'surf/rh.curv', - 'surf/lh.area', 'surf/rh.area', - 'label/lh.cortex.label', 'label/rh.cortex.label'], []), - ('smooth2', ['surf/lh.smoothwm', 'surf/rh.smoothwm'], []), - ('inflate2', ['surf/lh.inflated', 'surf/rh.inflated', - 'surf/lh.sulc', 'surf/rh.sulc'], []), - ('curvHK', ['surf/lh.white.H', 'surf/rh.white.H', - 'surf/lh.white.K', 'surf/rh.white.K', - 'surf/lh.inflated.H', 'surf/rh.inflated.H', - 'surf/lh.inflated.K', 'surf/rh.inflated.K'], []), - ('curvstats', ['stats/lh.curv.stats', 'stats/rh.curv.stats'], []), - # autorecon3 - ('sphere', ['surf/lh.sphere', 'surf/rh.sphere'], []), - ('surfreg', ['surf/lh.sphere.reg', 'surf/rh.sphere.reg'], []), - ('jacobian_white', ['surf/lh.jacobian_white', - 'surf/rh.jacobian_white'], []), - ('avgcurv', ['surf/lh.avg_curv', 'surf/rh.avg_curv'], []), - ('cortparc', ['label/lh.aparc.annot', 'label/rh.aparc.annot'], []), - ('pial', ['surf/lh.pial', 'surf/rh.pial', - 'surf/lh.curv.pial', 'surf/rh.curv.pial', - 'surf/lh.area.pial', 'surf/rh.area.pial', - 'surf/lh.thickness', 'surf/rh.thickness'], []), - ('cortribbon', ['mri/lh.ribbon.mgz', 'mri/rh.ribbon.mgz', - 'mri/ribbon.mgz'], []), - ('parcstats', ['stats/lh.aparc.astats', 'stats/rh.aparc.stats', - 'stats/aparc.annot.ctab'], []), - ('cortparc2', ['label/lh.aparc.a2009s.annot', - 'label/rh.aparc.a2009s.annot'], []), - ('parcstats2', ['stats/lh.aparc.a2009s.stats', - 'stats/rh.aparc.a2009s.stats', - 'stats/aparc.annot.a2009s.ctab'], []), - ('cortparc3', ['label/lh.aparc.DKTatlas.annot', - 'label/rh.aparc.DKTatlas.annot'], []), - ('parcstats3', ['stats/lh.aparc.DKTatlas.stats', - 'stats/rh.aparc.DKTatlas.stats', - 'stats/aparc.annot.DKTatlas.ctab'], []), - ('pctsurfcon', ['surf/lh.w-g.pct.mgh', 'surf/rh.w-g.pct.mgh'], []), - ('hyporelabel', ['mri/aseg.presurf.hypos.mgz'], []), - ('aparc2aseg', ['mri/aparc+aseg.mgz', - 'mri/aparc.a2009s+aseg.mgz', - 'mri/aparc.DKTatlas+aseg.mgz'], []), - ('apas2aseg', ['mri/aseg.mgz'], ['mri/aparc+aseg.mgz']), - ('segstats', ['stats/aseg.stats'], []), - ('wmparc', ['mri/wmparc.mgz', 'stats/wmparc.stats'], []), - ('balabels', ['BA.ctab', 'BA.thresh.ctab', - 'label/lh.entorhinal_exvivo.label', - 'label/rh.entorhinal_exvivo.label'], []), ] + if LooseVersion(FSVersion) < LooseVersion("6.0.0"): + _autorecon2_steps = [ + ('gcareg', ['mri/transforms/talairach.lta'], []), + ('canorm', ['mri/norm.mgz'], []), + ('careg', ['mri/transforms/talairach.m3z'], []), + ('careginv', ['mri/transforms/talairach.m3z.inv.x.mgz', + 'mri/transforms/talairach.m3z.inv.y.mgz', + 'mri/transforms/talairach.m3z.inv.z.mgz', + ], []), + ('rmneck', ['mri/nu_noneck.mgz'], []), + ('skull-lta', ['mri/transforms/talairach_with_skull_2.lta'], []), + ('calabel', ['mri/aseg.auto_noCCseg.mgz', + 'mri/aseg.auto.mgz', + 'mri/aseg.mgz'], []), + ('normalization2', ['mri/brain.mgz'], []), + ('maskbfs', ['mri/brain.finalsurfs.mgz'], []), + ('segmentation', ['mri/wm.seg.mgz', + 'mri/wm.asegedit.mgz', + 'mri/wm.mgz'], []), + ('fill', ['mri/filled.mgz', + # 'scripts/ponscc.cut.log', + ], []), + ('tessellate', ['surf/lh.orig.nofix', 'surf/rh.orig.nofix'], []), + ('smooth1', ['surf/lh.smoothwm.nofix', 'surf/rh.smoothwm.nofix'], + []), + ('inflate1', ['surf/lh.inflated.nofix', 'surf/rh.inflated.nofix'], + []), + ('qsphere', ['surf/lh.qsphere.nofix', 'surf/rh.qsphere.nofix'], + []), + ('fix', ['surf/lh.orig', 'surf/rh.orig'], []), + ('white', ['surf/lh.white', 'surf/rh.white', + 'surf/lh.curv', 'surf/rh.curv', + 'surf/lh.area', 'surf/rh.area', + 'label/lh.cortex.label', 'label/rh.cortex.label'], []), + ('smooth2', ['surf/lh.smoothwm', 'surf/rh.smoothwm'], []), + ('inflate2', ['surf/lh.inflated', 'surf/rh.inflated', + 'surf/lh.sulc', 'surf/rh.sulc', + 'surf/lh.inflated.H', 'surf/rh.inflated.H', + 'surf/lh.inflated.K', 'surf/rh.inflated.K'], []), + ] + _autorecon3_steps = [ + ('sphere', ['surf/lh.sphere', 'surf/rh.sphere'], []), + ('surfreg', ['surf/lh.sphere.reg', 'surf/rh.sphere.reg'], []), + ('jacobian_white', ['surf/lh.jacobian_white', + 'surf/rh.jacobian_white'], []), + ('avgcurv', ['surf/lh.avg_curv', 'surf/rh.avg_curv'], []), + ('cortparc', ['label/lh.aparc.annot', 'label/rh.aparc.annot'], []), + ('pial', ['surf/lh.pial', 'surf/rh.pial', + 'surf/lh.curv.pial', 'surf/rh.curv.pial', + 'surf/lh.area.pial', 'surf/rh.area.pial', + 'surf/lh.thickness', 'surf/rh.thickness'], []), + ('cortparc2', ['label/lh.aparc.a2009s.annot', + 'label/rh.aparc.a2009s.annot'], []), + ('parcstats2', ['stats/lh.aparc.a2009s.stats', + 'stats/rh.aparc.a2009s.stats', + 'stats/aparc.annot.a2009s.ctab'], []), + ('cortribbon', ['mri/lh.ribbon.mgz', 'mri/rh.ribbon.mgz', + 'mri/ribbon.mgz'], []), + ('segstats', ['stats/aseg.stats'], []), + ('aparc2aseg', ['mri/aparc+aseg.mgz', + 'mri/aparc.a2009s+aseg.mgz'], []), + ('wmparc', ['mri/wmparc.mgz', 'stats/wmparc.stats'], []), + ('balabels', ['BA.ctab', 'BA.thresh.ctab'], []), + ('label-exvivo-ec', ['label/lh.entorhinal_exvivo.label', + 'label/rh.entorhinal_exvivo.label'], []), + ] + else: + _autorecon2_steps = [ + ('gcareg', ['mri/transforms/talairach.lta'], []), + ('canorm', ['mri/norm.mgz'], []), + ('careg', ['mri/transforms/talairach.m3z'], []), + ('calabel', ['mri/aseg.auto_noCCseg.mgz', + 'mri/aseg.auto.mgz', + 'mri/aseg.mgz'], []), + ('normalization2', ['mri/brain.mgz'], []), + ('maskbfs', ['mri/brain.finalsurfs.mgz'], []), + ('segmentation', ['mri/wm.seg.mgz', + 'mri/wm.asegedit.mgz', + 'mri/wm.mgz'], []), + ('fill', ['mri/filled.mgz', + # 'scripts/ponscc.cut.log', + ], []), + ('tessellate', ['surf/lh.orig.nofix', 'surf/rh.orig.nofix'], []), + ('smooth1', ['surf/lh.smoothwm.nofix', 'surf/rh.smoothwm.nofix'], + []), + ('inflate1', ['surf/lh.inflated.nofix', 'surf/rh.inflated.nofix'], + []), + ('qsphere', ['surf/lh.qsphere.nofix', 'surf/rh.qsphere.nofix'], + []), + ('fix', ['surf/lh.orig', 'surf/rh.orig'], []), + ('white', ['surf/lh.white.preaparc', 'surf/rh.white.preaparc', + 'surf/lh.curv', 'surf/rh.curv', + 'surf/lh.area', 'surf/rh.area', + 'label/lh.cortex.label', 'label/rh.cortex.label'], []), + ('smooth2', ['surf/lh.smoothwm', 'surf/rh.smoothwm'], []), + ('inflate2', ['surf/lh.inflated', 'surf/rh.inflated', + 'surf/lh.sulc', 'surf/rh.sulc'], []), + ('curvHK', ['surf/lh.white.H', 'surf/rh.white.H', + 'surf/lh.white.K', 'surf/rh.white.K', + 'surf/lh.inflated.H', 'surf/rh.inflated.H', + 'surf/lh.inflated.K', 'surf/rh.inflated.K'], []), + ('curvstats', ['stats/lh.curv.stats', 'stats/rh.curv.stats'], []), + ] + _autorecon3_steps = [ + ('sphere', ['surf/lh.sphere', 'surf/rh.sphere'], []), + ('surfreg', ['surf/lh.sphere.reg', 'surf/rh.sphere.reg'], []), + ('jacobian_white', ['surf/lh.jacobian_white', + 'surf/rh.jacobian_white'], []), + ('avgcurv', ['surf/lh.avg_curv', 'surf/rh.avg_curv'], []), + ('cortparc', ['label/lh.aparc.annot', 'label/rh.aparc.annot'], []), + ('pial', ['surf/lh.pial', 'surf/rh.pial', + 'surf/lh.curv.pial', 'surf/rh.curv.pial', + 'surf/lh.area.pial', 'surf/rh.area.pial', + 'surf/lh.thickness', 'surf/rh.thickness'], []), + ('cortribbon', ['mri/lh.ribbon.mgz', 'mri/rh.ribbon.mgz', + 'mri/ribbon.mgz'], []), + ('parcstats', ['stats/lh.aparc.astats', 'stats/rh.aparc.stats', + 'stats/aparc.annot.ctab'], []), + ('cortparc2', ['label/lh.aparc.a2009s.annot', + 'label/rh.aparc.a2009s.annot'], []), + ('parcstats2', ['stats/lh.aparc.a2009s.stats', + 'stats/rh.aparc.a2009s.stats', + 'stats/aparc.annot.a2009s.ctab'], []), + ('cortparc3', ['label/lh.aparc.DKTatlas.annot', + 'label/rh.aparc.DKTatlas.annot'], []), + ('parcstats3', ['stats/lh.aparc.DKTatlas.stats', + 'stats/rh.aparc.DKTatlas.stats', + 'stats/aparc.annot.DKTatlas.ctab'], []), + ('pctsurfcon', ['surf/lh.w-g.pct.mgh', 'surf/rh.w-g.pct.mgh'], []), + ('hyporelabel', ['mri/aseg.presurf.hypos.mgz'], []), + ('aparc2aseg', ['mri/aparc+aseg.mgz', + 'mri/aparc.a2009s+aseg.mgz', + 'mri/aparc.DKTatlas+aseg.mgz'], []), + ('apas2aseg', ['mri/aseg.mgz'], ['mri/aparc+aseg.mgz']), + ('segstats', ['stats/aseg.stats'], []), + ('wmparc', ['mri/wmparc.mgz', 'stats/wmparc.stats'], []), + ('balabels', ['BA.ctab', 'BA.thresh.ctab', + 'label/lh.entorhinal_exvivo.label', + 'label/rh.entorhinal_exvivo.label'], []), + ] + + _steps = _autorecon1_steps + _autorecon2_steps + _autorecon3_steps def _gen_subjects_dir(self): return os.getcwd() From 03a79326030effc1e35fd5efa9c49e7f13f890d8 Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Tue, 31 Jan 2017 21:14:06 -0500 Subject: [PATCH 6/8] Test check_depends --- nipype/utils/filemanip.py | 2 +- nipype/utils/tests/test_filemanip.py | 40 +++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/nipype/utils/filemanip.py b/nipype/utils/filemanip.py index 697d92b2e7..ca5cd66f07 100644 --- a/nipype/utils/filemanip.py +++ b/nipype/utils/filemanip.py @@ -457,7 +457,7 @@ def check_depends(targets, dependencies): deps = filename_to_list(dependencies) return all(map(os.path.exists, tgts)) and \ min(map(os.path.getmtime, tgts)) > \ - max(map(os.path.getmtime, deps), default=0) + max(list(map(os.path.getmtime, deps)) + [0]) def save_json(filename, data): diff --git a/nipype/utils/tests/test_filemanip.py b/nipype/utils/tests/test_filemanip.py index f0dee52870..644a055f4b 100644 --- a/nipype/utils/tests/test_filemanip.py +++ b/nipype/utils/tests/test_filemanip.py @@ -5,7 +5,9 @@ from builtins import open import os -from tempfile import mkstemp +import time +from tempfile import mkstemp, mkdtemp +import shutil import warnings import pytest @@ -15,6 +17,7 @@ hash_rename, check_forhash, copyfile, copyfiles, filename_to_list, list_to_filename, + check_depends, split_filename, get_related_files) import numpy as np @@ -271,6 +274,41 @@ def test_list_to_filename(list, expected): assert x == expected +def test_check_depends(): + def touch(fname): + with open(fname, 'a'): + os.utime(fname, None) + + tmpdir = mkdtemp() + + dependencies = [os.path.join(tmpdir, str(i)) for i in range(3)] + targets = [os.path.join(tmpdir, str(i)) for i in range(3, 6)] + + # Targets newer than dependencies + for dep in dependencies: + touch(dep) + time.sleep(1) + for tgt in targets: + touch(tgt) + assert check_depends(targets, dependencies) + + # Targets older than newest dependency + time.sleep(1) + touch(dependencies[0]) + assert not check_depends(targets, dependencies) + + # Missing dependency + os.unlink(dependencies[0]) + try: + check_depends(targets, dependencies) + except OSError as e: + pass + else: + assert False, "Should raise OSError on missing dependency" + + shutil.rmtree(tmpdir) + + def test_json(): # Simple roundtrip test of json files, just a sanity check. adict = dict(a='one', c='three', b='two') From 2752945360d88514841651607b7aea86d9435327 Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Tue, 31 Jan 2017 21:16:56 -0500 Subject: [PATCH 7/8] Update changelog --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index fc37efb061..8720078b98 100644 --- a/CHANGES +++ b/CHANGES @@ -29,6 +29,7 @@ Upcoming release 0.13 * ENH: Added support for custom job submission check in SLURM (https://github.com/nipy/nipype/pull/1582) * ENH: Added ANTs interface CreateJacobianDeterminantImage; replaces deprecated JacobianDeterminant (https://github.com/nipy/nipype/pull/1654) +* ENH: Update ReconAll interface for FreeSurfer v6.0.0 (https://github.com/nipy/nipype/pull/1790) Release 0.12.1 (August 3, 2016) =============================== From 06a9eb919380d2176111c7334456682fa305e201 Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Tue, 7 Feb 2017 18:58:52 -0500 Subject: [PATCH 8/8] Add -parallel flag to ReconAll --- nipype/interfaces/freesurfer/preprocess.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nipype/interfaces/freesurfer/preprocess.py b/nipype/interfaces/freesurfer/preprocess.py index 73d8b3637c..2953963149 100644 --- a/nipype/interfaces/freesurfer/preprocess.py +++ b/nipype/interfaces/freesurfer/preprocess.py @@ -630,6 +630,8 @@ class ReconAllInputSpec(CommandLineInputSpec): desc='Use converted T2 to refine the cortical surface') openmp = traits.Int(argstr="-openmp %d", desc="Number of processors to use in parallel") + parallel = traits.Bool(argstr="-parallel", + desc="Enable parallel execution") subjects_dir = Directory(exists=True, argstr='-sd %s', hash_files=False, desc='path to subjects directory', genfile=True) flags = traits.Str(argstr='%s', desc='additional parameters')