Skip to content

Commit 3219fc6

Browse files
committed
Merge pull request #697 from satra/fix/reporting
WIP: Multiple fixes
2 parents 455766d + ba4036b commit 3219fc6

File tree

18 files changed

+532
-206
lines changed

18 files changed

+532
-206
lines changed

CHANGES

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,16 @@ Next release
3838
* ENH: Added simplified outputname generation for command line interfaces.
3939
* FIX: Cleaned up input and output spec metadata
4040

41+
* ENH: Allow ants use a single mask image
42+
* ENH: Create configuration option for parameterizing directories with hashes
43+
* ENH: arrange nodes by topological sort with disconnected subgraphs
44+
* ENH: uses the nidm iri namespace for uuids
45+
* ENH: remove old reporting webpage (this is a WIP i hope to finish in a day or two)
46+
47+
* FIX: example openfmri script now makes the contrast spec a hashed input
48+
* FIX: FILMGLS compatibility with FSL 5.0.5
49+
* FIX: Freesurfer recon-all resume now avoids setting inputs
50+
4151
Release 0.8.0 (May 8, 2013)
4252
===========================
4353

doc/users/config_file.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ Execution
114114
version information is available. Please notify developers or submit a
115115
patch.
116116

117+
*parameterize_dirs*
118+
If this is set to True, the node's output directory will contain full
119+
parameterization of any iterable, otherwise parameterizations over 32
120+
characters will be replaced by their hash. (possible values: ``true`` and
121+
``false``; default value: ``true``)
122+
117123
Example
118124
~~~~~~~
119125

doc/users/joinnode_and_itersource.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ the *unique* flag, e.g.:
7070

7171
::
7272

73-
d = pe.JoinNode(interface=D(), joinsource="b", unique=True, name="d")
73+
d = pe.JoinNode(interface=D(), joinsource="b", unique=True, name="d")
7474

7575
synchronize
7676
===========

examples/fmri_openfmri.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,9 @@ def analyze_openfmri_dataset(data_dir, subject=None, model_id=None,
129129
'task_id']),
130130
name='infosource')
131131
if subject is None:
132-
infosource.iterables = [('subject_id', subjects),
133-
('model_id', [model_id])]
132+
infosource.iterables = [('subject_id', subjects[:2]),
133+
('model_id', [model_id]),
134+
('task_id', [task_id])]
134135
else:
135136
infosource.iterables = [('subject_id',
136137
[subjects[subjects.index(subject)]]),
@@ -150,18 +151,22 @@ def analyze_openfmri_dataset(data_dir, subject=None, model_id=None,
150151

151152
datasource = pe.Node(nio.DataGrabber(infields=['subject_id', 'run_id',
152153
'task_id', 'model_id'],
153-
outfields=['anat', 'bold', 'behav']),
154+
outfields=['anat', 'bold', 'behav',
155+
'contrasts']),
154156
name='datasource')
155157
datasource.inputs.base_directory = data_dir
156158
datasource.inputs.template = '*'
157159
datasource.inputs.field_template = {'anat': '%s/anatomy/highres001.nii.gz',
158160
'bold': '%s/BOLD/task%03d_r*/bold.nii.gz',
159161
'behav': ('%s/model/model%03d/onsets/task%03d_'
160-
'run%03d/cond*.txt')}
162+
'run%03d/cond*.txt'),
163+
'contrasts': ('models/model%03d/'
164+
'task_contrasts.txt')}
161165
datasource.inputs.template_args = {'anat': [['subject_id']],
162166
'bold': [['subject_id', 'task_id']],
163167
'behav': [['subject_id', 'model_id',
164-
'task_id', 'run_id']]}
168+
'task_id', 'run_id']],
169+
'contrasts': [['model_id']]}
165170
datasource.inputs.sort_filelist = True
166171

167172
"""
@@ -192,11 +197,8 @@ def get_highpass(TR, hpcutoff):
192197
Setup a basic set of contrasts, a t-test per condition
193198
"""
194199

195-
def get_contrasts(base_dir, model_id, task_id, conds):
200+
def get_contrasts(contrast_file, task_id, conds):
196201
import numpy as np
197-
import os
198-
contrast_file = os.path.join(base_dir, 'models', 'model%03d' % model_id,
199-
'task_contrasts.txt')
200202
contrast_def = np.genfromtxt(contrast_file, dtype=object)
201203
contrasts = []
202204
for row in contrast_def:
@@ -207,12 +209,11 @@ def get_contrasts(base_dir, model_id, task_id, conds):
207209
contrasts.append(con)
208210
return contrasts
209211

210-
contrastgen = pe.Node(niu.Function(input_names=['base_dir', 'model_id',
212+
contrastgen = pe.Node(niu.Function(input_names=['contrast_file',
211213
'task_id', 'conds'],
212214
output_names=['contrasts'],
213215
function=get_contrasts),
214216
name='contrastgen')
215-
contrastgen.inputs.base_dir = data_dir
216217

217218
art = pe.MapNode(interface=ra.ArtifactDetect(use_differences=[True, False],
218219
use_norm=True,
@@ -232,7 +233,7 @@ def get_contrasts(base_dir, model_id, task_id, conds):
232233
wf.connect(datasource, 'behav', modelspec, 'event_files')
233234
wf.connect(subjinfo, 'TR', modelfit, 'inputspec.interscan_interval')
234235
wf.connect(subjinfo, 'conds', contrastgen, 'conds')
235-
wf.connect(infosource, 'model_id', contrastgen, 'model_id')
236+
wf.connect(datasource, 'contrasts', contrastgen, 'contrast_file')
236237
wf.connect(infosource, 'task_id', contrastgen, 'task_id')
237238
wf.connect(contrastgen, 'contrasts', modelfit, 'inputspec.contrasts')
238239

nipype/external/d3.v3.min.js

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nipype/interfaces/afni/base.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,14 +98,14 @@ class AFNICommandInputSpec(CommandLineInputSpec):
9898
out_file = File(name_template="%s_afni", desc='output image file name',
9999
argstr='-prefix %s',
100100
name_source=["in_file"])
101-
101+
102102
class AFNICommandOutputSpec(TraitedSpec):
103103
out_file = File(desc='output file',
104104
exists=True)
105105

106106

107107
class AFNICommand(CommandLine):
108-
108+
109109
input_spec = AFNICommandInputSpec
110110
_outputtype = None
111111

@@ -143,7 +143,7 @@ def set_default_output_type(cls, outputtype):
143143
cls._outputtype = outputtype
144144
else:
145145
raise AttributeError('Invalid AFNI outputtype: %s' % outputtype)
146-
146+
147147
def _overload_extension(self, value):
148148
path, base, _ = split_filename(value)
149149
return os.path.join(path, base + Info.outputtype_to_ext(self.inputs.outputtype))
@@ -157,5 +157,5 @@ def _list_outputs(self):
157157
if outputs[name]:
158158
_,_,ext = split_filename(outputs[name])
159159
if ext == "":
160-
outputs[name] = outputs[name] + "+orig.BRIK"
160+
outputs[name] = outputs[name] + "+orig.BRIK"
161161
return outputs

nipype/interfaces/ants/registration.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,11 @@ class RegistrationInputSpec(ANTSCommandInputSpec):
194194
usedefault=True, desc='image dimension (2 or 3)')
195195
fixed_image = InputMultiPath(File(exists=True), mandatory=True,
196196
desc='image to apply transformation to (generally a coregistered functional)')
197-
fixed_image_mask = File(requires=['moving_image_mask'],
198-
exists=True, desc='')
197+
fixed_image_mask = File(argstr='%s', exists=True,
198+
desc='mask used to limit registration region')
199199
moving_image = InputMultiPath(File(exists=True), mandatory=True,
200200
desc='image to apply transformation to (generally a coregistered functional)')
201-
moving_image_mask = File(argstr='%s', requires=['fixed_image_mask'],
201+
moving_image_mask = File(requires=['fixed_image_mask'],
202202
exists=True, desc='')
203203
initial_moving_transform = File(argstr='%s', exists=True, desc='',
204204
xor=['initial_moving_transform_com'])
@@ -558,8 +558,12 @@ def _formatCollapseLinearTransformsToFixedImageHeader(self):
558558
return '--collapse-linear-transforms-to-fixed-image-header 0'
559559

560560
def _format_arg(self, opt, spec, val):
561-
if opt == 'moving_image_mask':
562-
return '--masks [ %s, %s ]' % (self.inputs.fixed_image_mask, self.inputs.moving_image_mask)
561+
if opt == 'fixed_image_mask':
562+
if isdefined(self.inputs.moving_image_mask):
563+
return '--masks [ %s, %s ]' % (self.inputs.fixed_image_mask,
564+
self.inputs.moving_image_mask)
565+
else:
566+
return '--masks %s' % self.inputs.fixed_image_mask
563567
elif opt == 'transforms':
564568
return self._formatRegistration()
565569
elif opt == 'initial_moving_transform':

nipype/interfaces/freesurfer/preprocess.py

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -591,17 +591,22 @@ def _gen_filename(self, name):
591591

592592

593593
class ReconAllInputSpec(CommandLineInputSpec):
594-
subject_id = traits.Str("recon_all", argstr='-subjid %s', desc='subject name',
595-
usedefault=True)
594+
subject_id = traits.Str("recon_all", argstr='-subjid %s',
595+
desc='subject name', usedefault=True)
596596
directive = traits.Enum('all', 'autorecon1', 'autorecon2', 'autorecon2-cp',
597-
'autorecon2-wm', 'autorecon2-inflate1', 'autorecon2-perhemi',
598-
'autorecon3', 'localGI', 'qcache', argstr='-%s',
599-
desc='process directive', usedefault=True,
600-
position=0)
601-
hemi = traits.Enum('lh', 'rh', desc='hemisphere to process', argstr="-hemi %s")
597+
'autorecon2-wm', 'autorecon2-inflate1',
598+
'autorecon2-perhemi', 'autorecon3', 'localGI',
599+
'qcache', argstr='-%s', desc='process directive',
600+
usedefault=True, position=0)
601+
hemi = traits.Enum('lh', 'rh', desc='hemisphere to process',
602+
argstr="-hemi %s")
602603
T1_files = InputMultiPath(File(exists=True), argstr='-i %s...',
603604
desc='name of T1 file to process')
604-
subjects_dir = Directory(exists=True, argstr='-sd %s',
605+
T2_file = File(exists=True, argstr="-T2 %s", min_ver='5.3.0',
606+
desc='Use a T2 image to refine the cortical surface')
607+
openmp = traits.Int(argstr="-openmp %d",
608+
desc="Number of processors to use in parallel")
609+
subjects_dir = Directory(exists=True, argstr='-sd %s', hash_files=False,
605610
desc='path to subjects directory', genfile=True)
606611
flags = traits.Str(argstr='%s', desc='additional parameters')
607612

@@ -742,42 +747,54 @@ def _list_outputs(self):
742747
outputs = self._outputs().get()
743748

744749
outputs.update(FreeSurferSource(subject_id=self.inputs.subject_id,
745-
subjects_dir=subjects_dir, hemi=hemi)._list_outputs())
750+
subjects_dir=subjects_dir,
751+
hemi=hemi)._list_outputs())
746752
outputs['subject_id'] = self.inputs.subject_id
747753
outputs['subjects_dir'] = subjects_dir
748754
return outputs
749755

750-
@property
751-
def cmdline(self):
756+
def _is_resuming(self):
752757
subjects_dir = self.inputs.subjects_dir
753758
if not isdefined(subjects_dir):
754759
subjects_dir = self._gen_subjects_dir()
755-
if not os.path.isdir(
756-
os.path.join(subjects_dir,self.inputs.subject_id,'mri')):
757-
return super(ReconAll, self).cmdline
758-
self._check_mandatory_inputs()
759-
skip = ['T1_files']
760+
if os.path.isdir(os.path.join(subjects_dir, self.inputs.subject_id,
761+
'mri')):
762+
return True
763+
return False
764+
765+
def _format_arg(self, name, trait_spec, value):
766+
if name == 'T1_files':
767+
if self._is_resuming():
768+
return ''
769+
return super(ReconAll, self)._format_arg(name, trait_spec, value)
770+
771+
@property
772+
def cmdline(self):
773+
cmd = super(ReconAll, self).cmdline
774+
if not self._is_resuming():
775+
return cmd
760776
subjects_dir = self.inputs.subjects_dir
761777
if not isdefined(subjects_dir):
762778
subjects_dir = self._gen_subjects_dir()
779+
#cmd = cmd.replace(' -all ', ' -make all ')
780+
iflogger.info('Overriding recon-all directive')
763781
flags = []
764782
directive = 'all'
765783
for idx, step in enumerate(self._steps):
766784
step, outfiles = step
767-
if all([os.path.exists(os.path.join(subjects_dir,self.inputs.subject_id,f)) for f in outfiles]):
785+
if all([os.path.exists(os.path.join(subjects_dir,
786+
self.inputs.subject_id,f)) for
787+
f in outfiles]):
768788
flags.append('-no%s'%step)
769789
if idx > 4:
770790
directive = 'autorecon2'
771791
elif idx > 23:
772792
directive = 'autorecon3'
773793
else:
774794
flags.append('-%s'%step)
775-
self.inputs.args = ' '.join([self.inputs.args] + flags)
776-
self.inputs.directive = directive
777-
allargs = self._parse_inputs(skip=skip)
778-
allargs.insert(0, self.cmd)
779-
cmd = ' '.join(allargs)
780-
iflogger.info('resume recon-all : %s'%cmd)
795+
cmd = cmd.replace(' -%s ' % self.inputs.directive, ' -%s ' % directive)
796+
cmd += ' ' + ' '.join(flags)
797+
iflogger.info('resume recon-all : %s' % cmd)
781798
return cmd
782799

783800

nipype/interfaces/fsl/base.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@
2929
import os
3030
import warnings
3131

32-
from nipype.utils.filemanip import fname_presuffix
33-
from nipype.interfaces.base import (CommandLine, traits, CommandLineInputSpec,
34-
isdefined)
32+
from ...utils.filemanip import fname_presuffix
33+
from ..base import (CommandLine, traits, CommandLineInputSpec, isdefined)
3534

3635
warn = warnings.warn
3736
warnings.filterwarnings('always', category=UserWarning)

nipype/interfaces/fsl/model.py

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,16 @@
1818

1919
import numpy as np
2020

21-
from nipype.interfaces.fsl.base import (FSLCommand, FSLCommandInputSpec, Info)
22-
from nipype.interfaces.base import (load_template, File, traits, isdefined,
21+
from nibabel import load
22+
23+
from ... import LooseVersion
24+
from .base import (FSLCommand, FSLCommandInputSpec, Info)
25+
from ..base import (load_template, File, traits, isdefined,
2326
TraitedSpec, BaseInterface, Directory,
2427
InputMultiPath, OutputMultiPath,
2528
BaseInterfaceInputSpec)
26-
from nipype.utils.filemanip import (
27-
list_to_filename, filename_to_list, fname_presuffix)
28-
from nibabel import load
29-
from nipype.utils.misc import human_order_sorted
29+
from ...utils.filemanip import (list_to_filename, filename_to_list)
30+
from ...utils.misc import human_order_sorted
3031

3132
warn = warnings.warn
3233
warnings.filterwarnings('always', category=UserWarning)
@@ -473,9 +474,6 @@ def _list_outputs(self):
473474
return outputs
474475

475476

476-
# interface to fsl command line model fit routines
477-
# ohinds: 2009-12-28
478-
479477
class FILMGLSInputSpec(FSLCommandInputSpec):
480478
in_file = File(exists=True, mandatory=True, position=-3,
481479
argstr='%s',
@@ -513,6 +511,43 @@ class FILMGLSInputSpec(FSLCommandInputSpec):
513511
results_dir = Directory('results', argstr='-rn %s', usedefault=True,
514512
desc='directory to store results in')
515513

514+
class FILMGLSInputSpec505(FSLCommandInputSpec):
515+
in_file = File(exists=True, mandatory=True, position=-3,
516+
argstr='--in=%s', desc='input data file')
517+
design_file = File(exists=True, position=-2,
518+
argstr='--pd=%s', desc='design matrix file')
519+
threshold = traits.Range(default=1000., low=0.0, argstr='--thr=%f',
520+
position=-1, usedefault=True, desc='threshold')
521+
smooth_autocorr = traits.Bool(argstr='--sa',
522+
desc='Smooth auto corr estimates')
523+
mask_size = traits.Int(argstr='--ms=%d', desc="susan mask size")
524+
brightness_threshold = traits.Range(low=0, argstr='--epith=%d',
525+
desc=('susan brightness threshold, '
526+
'otherwise it is estimated'))
527+
full_data = traits.Bool(argstr='-v', desc='output full data')
528+
_estimate_xor = ['autocorr_estimate_only', 'fit_armodel', 'tukey_window',
529+
'multitaper_product', 'use_pava', 'autocorr_noestimate']
530+
autocorr_estimate_only = traits.Bool(argstr='--ac', xor=_estimate_xor,
531+
desc=('perform autocorrelation '
532+
'estimation only'))
533+
fit_armodel = traits.Bool(argstr='--ar', xor=_estimate_xor,
534+
desc=('fits autoregressive model - default is to '
535+
'use tukey with M=sqrt(numvols)'))
536+
tukey_window = traits.Int(argstr='--tukey=%d', xor=_estimate_xor,
537+
desc='tukey window size to estimate autocorr')
538+
multitaper_product = traits.Int(argstr='--mt=%d', xor=_estimate_xor,
539+
desc=('multitapering with slepian tapers '
540+
'and num is the time-bandwidth '
541+
'product'))
542+
use_pava = traits.Bool(argstr='--pava', desc='estimates autocorr using PAVA')
543+
autocorr_noestimate = traits.Bool(argstr='--noest', xor=_estimate_xor,
544+
desc='do not estimate autocorrs')
545+
output_pwdata = traits.Bool(argstr='--outputPWdata',
546+
desc=('output prewhitened data and average '
547+
'design matrix'))
548+
results_dir = Directory('results', argstr='--rn=%s', usedefault=True,
549+
desc='directory to store results in')
550+
516551

517552
class FILMGLSOutputSpec(TraitedSpec):
518553
param_estimates = OutputMultiPath(File(exists=True),
@@ -561,7 +596,11 @@ class FILMGLS(FSLCommand):
561596
"""
562597

563598
_cmd = 'film_gls'
564-
input_spec = FILMGLSInputSpec
599+
600+
if LooseVersion(Info.version()) > LooseVersion('5.0.4'):
601+
input_spec = FILMGLSInputSpec505
602+
else:
603+
input_spec = FILMGLSInputSpec
565604
output_spec = FILMGLSOutputSpec
566605

567606
def _get_pe_files(self, cwd):

0 commit comments

Comments
 (0)