Skip to content

Commit 9867d36

Browse files
committed
Merge pull request #1207 from chrisfilo/fix/spm_realign
SPM realign used to omit the first volume/run
2 parents e00c482 + df23a64 commit 9867d36

File tree

4 files changed

+105
-29
lines changed

4 files changed

+105
-29
lines changed

circle.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ test:
2929
timeout: 2600
3030
- set -o pipefail && cd doc && make html 2>&1 | tee ~/log.txt
3131
- cat ~/log.txt && if grep -q "ERROR" ~/log.txt; then false; else true; fi
32+
- . /usr/share/fsl/5.0/etc/fslconf/fsl.sh && python ~/nipype/tools/run_examples.py test_spm Linear workflow3d workflow4d:
33+
pwd: ../examples
34+
environment:
35+
SPMMCRCMD: "$HOME/spm12/run_spm12.sh $HOME/mcr/v85/ script"
36+
FORCE_SPMMCR: 1
37+
timeout: 1600
3238
- . /usr/share/fsl/5.0/etc/fslconf/fsl.sh && python ~/nipype/tools/run_examples.py fmri_fsl_feeds Linear l1pipeline:
3339
pwd: ../examples
3440
- . /usr/share/fsl/5.0/etc/fslconf/fsl.sh && python ~/nipype/tools/run_examples.py fmri_spm_dartel Linear level1 l2pipeline:

examples/test_spm.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import nipype.pipeline.engine as pe
2+
from nipype.interfaces import spm
3+
from nipype.interfaces import fsl
4+
from nipype.algorithms.misc import Gunzip
5+
import os
6+
7+
in_file = "feeds/data/fmri.nii.gz"
8+
9+
split = pe.Node(fsl.Split(dimension="t", output_type="NIFTI"), name="split")
10+
split.inputs.in_file = os.path.abspath(in_file)
11+
12+
stc = pe.Node(interface=spm.SliceTiming(), name='stc')
13+
stc.inputs.num_slices = 21
14+
stc.inputs.time_repetition = 1.0
15+
stc.inputs.time_acquisition = 2. - 2./32
16+
stc.inputs.slice_order = range(21,0,-1)
17+
stc.inputs.ref_slice = 10
18+
19+
realign_estimate = pe.Node(interface=spm.Realign(), name='realign_estimate')
20+
realign_estimate.inputs.jobtype = "estimate"
21+
22+
realign_write = pe.Node(interface=spm.Realign(), name='realign_write')
23+
realign_write.inputs.jobtype = "write"
24+
25+
realign_estwrite = pe.Node(interface=spm.Realign(), name='realign_estwrite')
26+
realign_estwrite.inputs.jobtype = "estwrite"
27+
realign_estwrite.inputs.register_to_mean = True
28+
29+
smooth = pe.Node(interface=spm.Smooth(), name = 'smooth')
30+
smooth.inputs.fwhm = [6, 6, 6]
31+
32+
workflow3d = pe.Workflow(name='test_3d')
33+
workflow3d.base_dir = "/tmp"
34+
35+
workflow3d.connect([(split, stc, [("out_files", "in_files")]),
36+
(stc, realign_estimate, [('timecorrected_files','in_files')]),
37+
(realign_estimate, realign_write, [('modified_in_files','in_files')]),
38+
(stc, realign_estwrite, [('timecorrected_files','in_files')]),
39+
(realign_write, smooth, [('realigned_files','in_files')])])
40+
41+
workflow3d.run()
42+
43+
44+
gunzip = pe.Node(Gunzip(), name="gunzip")
45+
gunzip.inputs.in_file = os.path.abspath(in_file)
46+
47+
stc = pe.Node(interface=spm.SliceTiming(), name='stc')
48+
stc.inputs.num_slices = 21
49+
stc.inputs.time_repetition = 1.0
50+
stc.inputs.time_acquisition = 2. - 2./32
51+
stc.inputs.slice_order = range(21,0,-1)
52+
stc.inputs.ref_slice = 10
53+
54+
realign_estimate = pe.Node(interface=spm.Realign(), name='realign_estimate')
55+
realign_estimate.inputs.jobtype = "estimate"
56+
57+
realign_write = pe.Node(interface=spm.Realign(), name='realign_write')
58+
realign_write.inputs.jobtype = "write"
59+
60+
realign_estwrite = pe.Node(interface=spm.Realign(), name='realign_estwrite')
61+
realign_estwrite.inputs.jobtype = "estwrite"
62+
63+
smooth = pe.Node(interface=spm.Smooth(), name = 'smooth')
64+
smooth.inputs.fwhm = [6, 6, 6]
65+
66+
workflow4d = pe.Workflow(name='test_4d')
67+
workflow4d.base_dir = "/tmp"
68+
69+
workflow4d.connect([(gunzip, stc, [("out_file", "in_files")]),
70+
(stc, realign_estimate, [('timecorrected_files','in_files')]),
71+
(realign_estimate, realign_write, [('modified_in_files','in_files')]),
72+
(stc, realign_estwrite, [('timecorrected_files','in_files')]),
73+
(realign_write, smooth, [('realigned_files','in_files')])])
74+
75+
workflow4d.run()

nipype/interfaces/spm/preprocess.py

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,8 @@ class RealignInputSpec(SPMCommandInputSpec):
123123
desc='gaussian smoothing kernel width')
124124
separation = traits.Range(low=0.0, field='eoptions.sep',
125125
desc='sampling separation in mm')
126-
register_to_mean = traits.Bool(True, field='eoptions.rtm',
127-
mandatory=True, usedefault=True,
128-
desc='Indicate whether realignment is done to the mean image')
126+
register_to_mean = traits.Bool(field='eoptions.rtm',
127+
desc='Indicate whether realignment is done to the mean image')
129128
weight_img = File(exists=True, field='eoptions.weight',
130129
desc='filename of weighting image')
131130
interp = traits.Range(low=0, high=7, field='eoptions.interp',
@@ -191,9 +190,13 @@ def _format_arg(self, opt, spec, val):
191190
"""Convert input to appropriate format for spm
192191
"""
193192
if opt == 'in_files':
193+
if self.inputs.jobtype == "write":
194+
separate_sessions = False
195+
else:
196+
separate_sessions = True
194197
return scans_for_fnames(val,
195-
keep4d=True,
196-
separate_sessions=True)
198+
keep4d=False,
199+
separate_sessions=separate_sessions)
197200
return super(Realign, self)._format_arg(opt, spec, val)
198201

199202
def _parse_inputs(self):
@@ -206,19 +209,21 @@ def _list_outputs(self):
206209
outputs = self._outputs().get()
207210
resliced_all = self.inputs.write_which[0] > 0
208211
resliced_mean = self.inputs.write_which[1] > 0
209-
if isdefined(self.inputs.in_files):
210-
outputs['realignment_parameters'] = []
211-
for imgf in self.inputs.in_files:
212-
if isinstance(imgf, list):
213-
tmp_imgf = imgf[0]
214-
else:
215-
tmp_imgf = imgf
216-
outputs['realignment_parameters'].append(fname_presuffix(tmp_imgf,
217-
prefix='rp_',
218-
suffix='.txt',
219-
use_ext=False))
220-
if not isinstance(imgf, list) and func_is_3d(imgf):
221-
break
212+
213+
if self.inputs.jobtype != "write":
214+
if isdefined(self.inputs.in_files):
215+
outputs['realignment_parameters'] = []
216+
for imgf in self.inputs.in_files:
217+
if isinstance(imgf, list):
218+
tmp_imgf = imgf[0]
219+
else:
220+
tmp_imgf = imgf
221+
outputs['realignment_parameters'].append(fname_presuffix(tmp_imgf,
222+
prefix='rp_',
223+
suffix='.txt',
224+
use_ext=False))
225+
if not isinstance(imgf, list) and func_is_3d(imgf):
226+
break
222227
if self.inputs.jobtype == "estimate":
223228
outputs['realigned_files'] = self.inputs.in_files
224229
if self.inputs.jobtype == "estimate" or self.inputs.jobtype == "estwrite":
@@ -240,18 +245,10 @@ def _list_outputs(self):
240245
for i, inner_imgf in enumerate(filename_to_list(imgf)):
241246
newfile = fname_presuffix(inner_imgf,
242247
prefix=self.inputs.out_prefix)
243-
if os.path.exists(newfile):
244-
realigned_run.append(newfile)
245-
continue
246-
if (idx == 0) and (i == 0) and \
247-
func_is_3d(inner_imgf):
248-
realigned_run.append(fname_presuffix(inner_imgf,
249-
prefix=''))
248+
realigned_run.append(newfile)
250249
else:
251250
realigned_run = fname_presuffix(imgf,
252251
prefix=self.inputs.out_prefix)
253-
if (idx == 0) and func_is_3d(imgf):
254-
realigned_run = fname_presuffix(imgf, prefix='')
255252
outputs['realigned_files'].append(realigned_run)
256253
return outputs
257254

nipype/interfaces/spm/tests/test_auto_Realign.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ def test_Realign_inputs():
2626
quality=dict(field='eoptions.quality',
2727
),
2828
register_to_mean=dict(field='eoptions.rtm',
29-
mandatory=True,
30-
usedefault=True,
3129
),
3230
separation=dict(field='eoptions.sep',
3331
),

0 commit comments

Comments
 (0)