Skip to content

Commit bfdb164

Browse files
authored
Merge pull request #1991 from effigies/enh/reconall_directives
ENH: Update multi-stage recon-all directives
2 parents 4b9838b + 8fcc097 commit bfdb164

File tree

1 file changed

+161
-98
lines changed

1 file changed

+161
-98
lines changed

nipype/interfaces/freesurfer/preprocess.py

Lines changed: 161 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -611,10 +611,18 @@ def _gen_filename(self, name):
611611
class ReconAllInputSpec(CommandLineInputSpec):
612612
subject_id = traits.Str("recon_all", argstr='-subjid %s',
613613
desc='subject name', usedefault=True)
614-
directive = traits.Enum('all', 'autorecon1', 'autorecon2', 'autorecon2-cp',
615-
'autorecon2-wm', 'autorecon2-inflate1',
616-
'autorecon2-perhemi', 'autorecon3', 'localGI',
617-
'qcache', argstr='-%s', desc='process directive',
614+
directive = traits.Enum('all', 'autorecon1',
615+
# autorecon2 variants
616+
'autorecon2', 'autorecon2-volonly',
617+
'autorecon2-perhemi', 'autorecon2-inflate1',
618+
'autorecon2-cp', 'autorecon2-wm',
619+
# autorecon3 variants
620+
'autorecon3', 'autorecon3-T2pial',
621+
# Mix of autorecon2 and autorecon3 steps
622+
'autorecon-pial', 'autorecon-hemi',
623+
# Not "multi-stage flags"
624+
'localGI', 'qcache',
625+
argstr='-%s', desc='process directive',
618626
usedefault=True, position=0)
619627
hemi = traits.Enum('lh', 'rh', desc='hemisphere to process',
620628
argstr="-hemi %s")
@@ -709,6 +717,38 @@ class ReconAll(CommandLine):
709717
>>> reconall.inputs.flags = ["-cw256", "-qcache"]
710718
>>> reconall.cmdline # doctest: +ALLOW_UNICODE
711719
'recon-all -all -i structural.nii -cw256 -qcache -subjid foo -sd .'
720+
721+
Hemisphere may be specified regardless of directive:
722+
723+
>>> reconall.inputs.flags = []
724+
>>> reconall.inputs.hemi = 'lh'
725+
>>> reconall.cmdline # doctest: +ALLOW_UNICODE
726+
'recon-all -all -i structural.nii -hemi lh -subjid foo -sd .'
727+
728+
``-autorecon-hemi`` uses the ``-hemi`` input to specify the hemisphere
729+
to operate upon:
730+
731+
>>> reconall.inputs.directive = 'autorecon-hemi'
732+
>>> reconall.cmdline # doctest: +ALLOW_UNICODE
733+
'recon-all -autorecon-hemi lh -i structural.nii -subjid foo -sd .'
734+
735+
Hippocampal subfields can accept T1 and T2 images:
736+
737+
>>> reconall_subfields = ReconAll()
738+
>>> reconall_subfields.inputs.subject_id = 'foo'
739+
>>> reconall_subfields.inputs.directive = 'all'
740+
>>> reconall_subfields.inputs.subjects_dir = '.'
741+
>>> reconall_subfields.inputs.T1_files = 'structural.nii'
742+
>>> reconall_subfields.inputs.hippocampal_subfields_T1 = True
743+
>>> reconall_subfields.cmdline # doctest: +ALLOW_UNICODE
744+
'recon-all -all -i structural.nii -hippocampal-subfields-T1 -subjid foo -sd .'
745+
>>> reconall_subfields.inputs.hippocampal_subfields_T2 = (
746+
... 'structural.nii', 'test')
747+
>>> reconall_subfields.cmdline # doctest: +ALLOW_UNICODE
748+
'recon-all -all -i structural.nii -hippocampal-subfields-T1T2 structural.nii test -subjid foo -sd .'
749+
>>> reconall_subfields.inputs.hippocampal_subfields_T1 = False
750+
>>> reconall_subfields.cmdline # doctest: +ALLOW_UNICODE
751+
'recon-all -all -i structural.nii -hippocampal-subfields-T2 structural.nii test -subjid foo -sd .'
712752
"""
713753

714754
_cmd = 'recon-all'
@@ -744,7 +784,7 @@ class ReconAll(CommandLine):
744784
'mri/brainmask.mgz'], []),
745785
]
746786
if Info.looseversion() < LooseVersion("6.0.0"):
747-
_autorecon2_steps = [
787+
_autorecon2_volonly_steps = [
748788
('gcareg', ['mri/transforms/talairach.lta'], []),
749789
('canorm', ['mri/norm.mgz'], []),
750790
('careg', ['mri/transforms/talairach.m3z'], []),
@@ -765,65 +805,51 @@ class ReconAll(CommandLine):
765805
('fill', ['mri/filled.mgz',
766806
# 'scripts/ponscc.cut.log',
767807
], []),
768-
('tessellate', ['surf/lh.orig.nofix', 'surf/rh.orig.nofix'], []),
769-
('smooth1', ['surf/lh.smoothwm.nofix', 'surf/rh.smoothwm.nofix'],
770-
[]),
771-
('inflate1', ['surf/lh.inflated.nofix', 'surf/rh.inflated.nofix'],
772-
[]),
773-
('qsphere', ['surf/lh.qsphere.nofix', 'surf/rh.qsphere.nofix'],
774-
[]),
775-
('fix', ['surf/lh.orig', 'surf/rh.orig'], []),
776-
('white', ['surf/lh.white', 'surf/rh.white',
777-
'surf/lh.curv', 'surf/rh.curv',
778-
'surf/lh.area', 'surf/rh.area',
779-
'label/lh.cortex.label', 'label/rh.cortex.label'], []),
780-
('smooth2', ['surf/lh.smoothwm', 'surf/rh.smoothwm'], []),
781-
('inflate2', ['surf/lh.inflated', 'surf/rh.inflated',
782-
'surf/lh.sulc', 'surf/rh.sulc',
783-
'surf/lh.inflated.H', 'surf/rh.inflated.H',
784-
'surf/lh.inflated.K', 'surf/rh.inflated.K'], []),
808+
]
809+
_autorecon2_lh_steps = [
810+
('tessellate', ['surf/lh.orig.nofix'], []),
811+
('smooth1', ['surf/lh.smoothwm.nofix'], []),
812+
('inflate1', ['surf/lh.inflated.nofix'], []),
813+
('qsphere', ['surf/lh.qsphere.nofix'], []),
814+
('fix', ['surf/lh.orig'], []),
815+
('white', ['surf/lh.white', 'surf/lh.curv', 'surf/lh.area',
816+
'label/lh.cortex.label'], []),
817+
('smooth2', ['surf/lh.smoothwm'], []),
818+
('inflate2', ['surf/lh.inflated', 'surf/lh.sulc',
819+
'surf/lh.inflated.H', 'surf/lh.inflated.K'], []),
785820
# Undocumented in ReconAllTableStableV5.3
786-
('curvstats', ['stats/lh.curv.stats', 'stats/rh.curv.stats'], []),
821+
('curvstats', ['stats/lh.curv.stats'], []),
787822
]
788-
_autorecon3_steps = [
789-
('sphere', ['surf/lh.sphere', 'surf/rh.sphere'], []),
790-
('surfreg', ['surf/lh.sphere.reg', 'surf/rh.sphere.reg'], []),
791-
('jacobian_white', ['surf/lh.jacobian_white',
792-
'surf/rh.jacobian_white'], []),
793-
('avgcurv', ['surf/lh.avg_curv', 'surf/rh.avg_curv'], []),
794-
('cortparc', ['label/lh.aparc.annot', 'label/rh.aparc.annot'], []),
795-
('pial', ['surf/lh.pial', 'surf/rh.pial',
796-
'surf/lh.curv.pial', 'surf/rh.curv.pial',
797-
'surf/lh.area.pial', 'surf/rh.area.pial',
798-
'surf/lh.thickness', 'surf/rh.thickness'], []),
823+
_autorecon3_lh_steps = [
824+
('sphere', ['surf/lh.sphere'], []),
825+
('surfreg', ['surf/lh.sphere.reg'], []),
826+
('jacobian_white', ['surf/lh.jacobian_white'], []),
827+
('avgcurv', ['surf/lh.avg_curv'], []),
828+
('cortparc', ['label/lh.aparc.annot'], []),
829+
('pial', ['surf/lh.pial', 'surf/lh.curv.pial', 'surf/lh.area.pial',
830+
'surf/lh.thickness'], []),
799831
# Misnamed outputs in ReconAllTableStableV5.3: ?h.w-c.pct.mgz
800-
('pctsurfcon', ['surf/lh.w-g.pct.mgh', 'surf/rh.w-g.pct.mgh'], []),
801-
('parcstats', ['stats/lh.aparc.stats', 'stats/rh.aparc.stats',
802-
'label/aparc.annot.a2009s.ctab'], []),
803-
('cortparc2', ['label/lh.aparc.a2009s.annot',
804-
'label/rh.aparc.a2009s.annot'], []),
805-
('parcstats2', ['stats/lh.aparc.a2009s.stats',
806-
'stats/rh.aparc.a2009s.stats',
807-
'label/aparc.annot.a2009s.ctab'], []),
832+
('pctsurfcon', ['surf/lh.w-g.pct.mgh'], []),
833+
('parcstats', ['stats/lh.aparc.stats'], []),
834+
('cortparc2', ['label/lh.aparc.a2009s.annot'], []),
835+
('parcstats2', ['stats/lh.aparc.a2009s.stats'], []),
808836
# Undocumented in ReconAllTableStableV5.3
809-
('cortparc3', ['label/lh.aparc.DKTatlas40.annot',
810-
'label/rh.aparc.DKTatlas40.annot'], []),
837+
('cortparc3', ['label/lh.aparc.DKTatlas40.annot'], []),
811838
# Undocumented in ReconAllTableStableV5.3
812-
('parcstats3', ['stats/lh.aparc.a2009s.stats',
813-
'stats/rh.aparc.a2009s.stats',
814-
'label/aparc.annot.a2009s.ctab'], []),
839+
('parcstats3', ['stats/lh.aparc.a2009s.stats'], []),
840+
('label-exvivo-ec', ['label/lh.entorhinal_exvivo.label'], []),
841+
]
842+
_autorecon3_added_steps = [
815843
('cortribbon', ['mri/lh.ribbon.mgz', 'mri/rh.ribbon.mgz',
816844
'mri/ribbon.mgz'], []),
817845
('segstats', ['stats/aseg.stats'], []),
818846
('aparc2aseg', ['mri/aparc+aseg.mgz',
819847
'mri/aparc.a2009s+aseg.mgz'], []),
820848
('wmparc', ['mri/wmparc.mgz', 'stats/wmparc.stats'], []),
821849
('balabels', ['label/BA.ctab', 'label/BA.thresh.ctab'], []),
822-
('label-exvivo-ec', ['label/lh.entorhinal_exvivo.label',
823-
'label/rh.entorhinal_exvivo.label'], []),
824850
]
825851
else:
826-
_autorecon2_steps = [
852+
_autorecon2_volonly_steps = [
827853
('gcareg', ['mri/transforms/talairach.lta'], []),
828854
('canorm', ['mri/norm.mgz'], []),
829855
('careg', ['mri/transforms/talairach.m3z'], []),
@@ -838,53 +864,39 @@ class ReconAll(CommandLine):
838864
('fill', ['mri/filled.mgz',
839865
# 'scripts/ponscc.cut.log',
840866
], []),
841-
('tessellate', ['surf/lh.orig.nofix', 'surf/rh.orig.nofix'], []),
842-
('smooth1', ['surf/lh.smoothwm.nofix', 'surf/rh.smoothwm.nofix'],
843-
[]),
844-
('inflate1', ['surf/lh.inflated.nofix', 'surf/rh.inflated.nofix'],
845-
[]),
846-
('qsphere', ['surf/lh.qsphere.nofix', 'surf/rh.qsphere.nofix'],
847-
[]),
848-
('fix', ['surf/lh.orig', 'surf/rh.orig'], []),
849-
('white', ['surf/lh.white.preaparc', 'surf/rh.white.preaparc',
850-
'surf/lh.curv', 'surf/rh.curv',
851-
'surf/lh.area', 'surf/rh.area',
852-
'label/lh.cortex.label', 'label/rh.cortex.label'], []),
853-
('smooth2', ['surf/lh.smoothwm', 'surf/rh.smoothwm'], []),
854-
('inflate2', ['surf/lh.inflated', 'surf/rh.inflated',
855-
'surf/lh.sulc', 'surf/rh.sulc'], []),
856-
('curvHK', ['surf/lh.white.H', 'surf/rh.white.H',
857-
'surf/lh.white.K', 'surf/rh.white.K',
858-
'surf/lh.inflated.H', 'surf/rh.inflated.H',
859-
'surf/lh.inflated.K', 'surf/rh.inflated.K'], []),
860-
('curvstats', ['stats/lh.curv.stats', 'stats/rh.curv.stats'], []),
861867
]
862-
_autorecon3_steps = [
863-
('sphere', ['surf/lh.sphere', 'surf/rh.sphere'], []),
864-
('surfreg', ['surf/lh.sphere.reg', 'surf/rh.sphere.reg'], []),
865-
('jacobian_white', ['surf/lh.jacobian_white',
866-
'surf/rh.jacobian_white'], []),
867-
('avgcurv', ['surf/lh.avg_curv', 'surf/rh.avg_curv'], []),
868-
('cortparc', ['label/lh.aparc.annot', 'label/rh.aparc.annot'], []),
869-
('pial', ['surf/lh.pial', 'surf/rh.pial',
870-
'surf/lh.curv.pial', 'surf/rh.curv.pial',
871-
'surf/lh.area.pial', 'surf/rh.area.pial',
872-
'surf/lh.thickness', 'surf/rh.thickness'], []),
868+
_autorecon2_lh_steps = [
869+
('tessellate', ['surf/lh.orig.nofix'], []),
870+
('smooth1', ['surf/lh.smoothwm.nofix'], []),
871+
('inflate1', ['surf/lh.inflated.nofix'], []),
872+
('qsphere', ['surf/lh.qsphere.nofix'], []),
873+
('fix', ['surf/lh.orig'], []),
874+
('white', ['surf/lh.white.preaparc', 'surf/lh.curv',
875+
'surf/lh.area', 'label/lh.cortex.label'], []),
876+
('smooth2', ['surf/lh.smoothwm'], []),
877+
('inflate2', ['surf/lh.inflated', 'surf/lh.sulc'], []),
878+
('curvHK', ['surf/lh.white.H', 'surf/lh.white.K',
879+
'surf/lh.inflated.H', 'surf/lh.inflated.K'], []),
880+
('curvstats', ['stats/lh.curv.stats'], []),
881+
]
882+
_autorecon3_lh_steps = [
883+
('sphere', ['surf/lh.sphere'], []),
884+
('surfreg', ['surf/lh.sphere.reg'], []),
885+
('jacobian_white', ['surf/lh.jacobian_white'], []),
886+
('avgcurv', ['surf/lh.avg_curv'], []),
887+
('cortparc', ['label/lh.aparc.annot'], []),
888+
('pial', ['surf/lh.pial', 'surf/lh.curv.pial',
889+
'surf/lh.area.pial', 'surf/lh.thickness'], []),
890+
('parcstats', ['stats/lh.aparc.stats'], []),
891+
('cortparc2', ['label/lh.aparc.a2009s.annot'], []),
892+
('parcstats2', ['stats/lh.aparc.a2009s.stats'], []),
893+
('cortparc3', ['label/lh.aparc.DKTatlas.annot'], []),
894+
('parcstats3', ['stats/lh.aparc.DKTatlas.stats'], []),
895+
('pctsurfcon', ['surf/lh.w-g.pct.mgh'], []),
896+
]
897+
_autorecon3_added_steps = [
873898
('cortribbon', ['mri/lh.ribbon.mgz', 'mri/rh.ribbon.mgz',
874899
'mri/ribbon.mgz'], []),
875-
('parcstats', ['stats/lh.aparc.stats', 'stats/rh.aparc.stats',
876-
'label/aparc.annot.ctab'], []),
877-
('cortparc2', ['label/lh.aparc.a2009s.annot',
878-
'label/rh.aparc.a2009s.annot'], []),
879-
('parcstats2', ['stats/lh.aparc.a2009s.stats',
880-
'stats/rh.aparc.a2009s.stats',
881-
'label/aparc.annot.a2009s.ctab'], []),
882-
('cortparc3', ['label/lh.aparc.DKTatlas.annot',
883-
'label/rh.aparc.DKTatlas.annot'], []),
884-
('parcstats3', ['stats/lh.aparc.DKTatlas.stats',
885-
'stats/rh.aparc.DKTatlas.stats',
886-
'label/aparc.annot.DKTatlas.ctab'], []),
887-
('pctsurfcon', ['surf/lh.w-g.pct.mgh', 'surf/rh.w-g.pct.mgh'], []),
888900
('hyporelabel', ['mri/aseg.presurf.hypos.mgz'], []),
889901
('aparc2aseg', ['mri/aparc+aseg.mgz',
890902
'mri/aparc.a2009s+aseg.mgz',
@@ -900,6 +912,30 @@ class ReconAll(CommandLine):
900912
'label/rh.entorhinal_exvivo.label'], []),
901913
]
902914

915+
# Fill out autorecon2 steps
916+
_autorecon2_rh_steps = [
917+
(step, [out.replace('lh', 'rh') for out in outs], ins)
918+
for step, outs, ins in _autorecon2_lh_steps]
919+
_autorecon2_perhemi_steps = [
920+
(step, [of for out in outs
921+
for of in (out, out.replace('lh', 'rh'))], ins)
922+
for step, outs, ins in _autorecon2_lh_steps]
923+
_autorecon2_steps = _autorecon2_volonly_steps + _autorecon2_perhemi_steps
924+
925+
# Fill out autorecon3 steps
926+
_autorecon3_rh_steps = [
927+
(step, [out.replace('lh', 'rh') for out in outs], ins)
928+
for step, outs, ins in _autorecon3_lh_steps]
929+
_autorecon3_perhemi_steps = [
930+
(step, [of for out in outs
931+
for of in (out, out.replace('lh', 'rh'))], ins)
932+
for step, outs, ins in _autorecon3_lh_steps]
933+
_autorecon3_steps = _autorecon3_perhemi_steps + _autorecon3_added_steps
934+
935+
# Fill out autorecon-hemi lh/rh steps
936+
_autorecon_lh_steps = (_autorecon2_lh_steps + _autorecon3_lh_steps)
937+
_autorecon_rh_steps = (_autorecon2_rh_steps + _autorecon3_rh_steps)
938+
903939
_steps = _autorecon1_steps + _autorecon2_steps + _autorecon3_steps
904940

905941
_binaries = ['talairach', 'mri_normalize', 'mri_watershed',
@@ -955,14 +991,24 @@ def _is_resuming(self):
955991
def _format_arg(self, name, trait_spec, value):
956992
if name == 'T1_files':
957993
if self._is_resuming():
958-
return ''
994+
return None
959995
if name == 'hippocampal_subfields_T1' and \
960996
isdefined(self.inputs.hippocampal_subfields_T2):
961-
return ''
997+
return None
962998
if all((name == 'hippocampal_subfields_T2',
963999
isdefined(self.inputs.hippocampal_subfields_T1) and
9641000
self.inputs.hippocampal_subfields_T1)):
965-
trait_spec.argstr = trait_spec.argstr.replace('T2', 'T1T2')
1001+
argstr = trait_spec.argstr.replace('T2', 'T1T2')
1002+
return argstr % value
1003+
if name == 'directive' and value == 'autorecon-hemi':
1004+
if not isdefined(self.inputs.hemi):
1005+
raise ValueError("Directive 'autorecon-hemi' requires hemi "
1006+
"input to be set")
1007+
value += ' ' + self.inputs.hemi
1008+
if all((name == 'hemi',
1009+
isdefined(self.inputs.directive) and
1010+
self.inputs.directive == 'autorecon-hemi')):
1011+
return None
9661012
return super(ReconAll, self)._format_arg(name, trait_spec, value)
9671013

9681014
@property
@@ -985,8 +1031,25 @@ def cmdline(self):
9851031
steps = []
9861032
elif directive == 'autorecon1':
9871033
steps = self._autorecon1_steps
1034+
elif directive == 'autorecon2-volonly':
1035+
steps = self._autorecon2_volonly_steps
1036+
elif directive == 'autorecon2-perhemi':
1037+
steps = self._autorecon2_perhemi_steps
9881038
elif directive.startswith('autorecon2'):
989-
steps = self._autorecon2_steps
1039+
if isdefined(self.inputs.hemi):
1040+
if self.inputs.hemi == 'lh':
1041+
steps = (self._autorecon2_volonly_steps +
1042+
self._autorecon2_lh_steps)
1043+
else:
1044+
steps = (self._autorecon2_volonly_steps +
1045+
self._autorecon2_rh_steps)
1046+
else:
1047+
steps = self._autorecon2_steps
1048+
elif directive == 'autorecon-hemi':
1049+
if self.inputs.hemi == 'lh':
1050+
steps = self._autorecon_lh_steps
1051+
else:
1052+
steps = self._autorecon_rh_steps
9901053
elif directive == 'autorecon3':
9911054
steps = self._autorecon3_steps
9921055
else:

0 commit comments

Comments
 (0)