Skip to content

Commit 24b87f3

Browse files
committed
Merge pull request #663 from satra/fix/spm_mcr
Fix/spm mcr
2 parents db1fb83 + 984a383 commit 24b87f3

File tree

7 files changed

+112
-45
lines changed

7 files changed

+112
-45
lines changed

CHANGES

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ Next release
2525
- FA created output files with erroneous extension
2626

2727
* FIX: Deals properly with 3d files in SPM Realign
28+
* FIX: SPM with MCR fixed
2829

2930
* API: 'name' is now a positional argument for Workflow, Node, and MapNode constructors
31+
* API: SPM now defaults to SPM8 or SPM12b job format
3032

3133
Release 0.8.0 (May 8, 2013)
3234
===========================

doc/users/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
joinnode_and_itersource
3535
model_specification
3636
saving_workflows
37-
37+
spmmcr
3838

3939

4040

doc/users/spmmcr.rst

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
.. _spmmcr:
2+
3+
====================================
4+
Using SPM with MATLAB Common Runtime
5+
====================================
6+
7+
In order to use the standalone MCR version of spm, you need to ensure that
8+
the following commands are executed at the beginning of your script:
9+
10+
.. testcode::
11+
12+
from nipype import spm
13+
matlab_cmd = '/path/to/run_spm8.sh /path/to/Compiler_Runtime/v713/ script'
14+
spm.SPMCommand.set_mlab_paths(matlab_cmd=matlab_cmd, use_mcr=True)
15+
16+
you can test by calling:
17+
18+
.. testcode::
19+
20+
spm.SPMCommand().version
21+
22+
Information about the MCR version of SPM8 can be found at:
23+
24+
http://en.wikibooks.org/wiki/SPM/Standalone

examples/fmri_spm.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,14 @@
1515
1616
Import necessary modules from nipype."""
1717

18+
from nipype import spm, fsl
19+
20+
# In order to use this example with SPM's matlab common runtime
21+
# matlab_cmd = ('/Users/satra/Downloads/spm8/run_spm8.sh '
22+
# '/Applications/MATLAB/MATLAB_Compiler_Runtime/v713/ script')
23+
# spm.SPMCommand.set_mlab_paths(matlab_cmd=matlab_cmd, use_mcr=True)
24+
1825
import nipype.interfaces.io as nio # Data i/o
19-
import nipype.interfaces.spm as spm # spm
20-
import nipype.interfaces.matlab as mlab # how to run matlab
21-
import nipype.interfaces.fsl as fsl # fsl
2226
import nipype.interfaces.utility as util # utility
2327
import nipype.pipeline.engine as pe # pypeline engine
2428
import nipype.algorithms.rapidart as ra # artifact detection
@@ -40,7 +44,8 @@
4044
fsl.FSLCommand.set_default_output_type('NIFTI')
4145

4246
# Set the way matlab should be called
43-
mlab.MatlabCommand.set_default_matlab_cmd("matlab -nodesktop -nosplash")
47+
# import nipype.interfaces.matlab as mlab # how to run matlab
48+
# mlab.MatlabCommand.set_default_matlab_cmd("matlab -nodesktop -nosplash")
4449

4550
"""The nipype tutorial contains data for two subjects. Subject data
4651
is in two subdirectories, ``s1`` and ``s2``. Each subject directory
@@ -382,7 +387,7 @@ def getstripdir(subject_id):
382387
"""
383388

384389
if __name__ == '__main__':
385-
l1pipeline.run()
390+
l1pipeline.run('MultiProc')
386391
# l2pipeline.run()
387392
# l1pipeline.write_graph()
388393

nipype/interfaces/spm/base.py

Lines changed: 67 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
22
# vi: set ft=python sts=4 ts=4 sw=4 et:
3-
"""The spm module provides basic functions for interfacing with SPM tools."""
3+
"""The spm module provides basic functions for interfacing with SPM tools.
4+
5+
In order to use the standalone MCR version of spm, you need to ensure that
6+
the following commands are executed at the beginning of your script::
7+
8+
from nipype import spm
9+
matlab_cmd = '/path/to/run_spm8.sh /path/to/Compiler_Runtime/v713/ script'
10+
spm.SPMCommand.set_mlab_paths(matlab_cmd=matlab_cmd, use_mcr=True)
11+
12+
you can test by calling::
13+
14+
spm.SPMCommand().version
15+
"""
416

517
__docformat__ = 'restructuredtext'
618

@@ -111,7 +123,7 @@ class Info(object):
111123
"""Handles SPM version information
112124
"""
113125
@staticmethod
114-
def version(matlab_cmd=None):
126+
def version(matlab_cmd=None, paths=None, use_mcr=None):
115127
"""Returns the path to the SPM directory in the Matlab path
116128
If path not found, returns None.
117129
@@ -135,6 +147,15 @@ def version(matlab_cmd=None):
135147
except:
136148
matlab_cmd = 'matlab -nodesktop -nosplash'
137149
mlab = MatlabCommand(matlab_cmd=matlab_cmd)
150+
mlab.inputs.mfile = False
151+
if paths:
152+
mlab.inputs.paths = paths
153+
if use_mcr:
154+
mlab.inputs.nodesktop = Undefined
155+
mlab.inputs.nosplash = Undefined
156+
mlab.inputs.single_comp_thread = Undefined
157+
mlab.inputs.mfile = True
158+
mlab.inputs.uses_mcr = True
138159
mlab.inputs.script = """
139160
if isempty(which('spm')),
140161
throw(MException('SPMCheck:NotFound','SPM not in matlab path'));
@@ -144,7 +165,6 @@ def version(matlab_cmd=None):
144165
fprintf(1, 'NIPYPE path:%s|name:%s|release:%s', spm_path, name, version);
145166
exit;
146167
"""
147-
mlab.inputs.mfile = False
148168
try:
149169
out = mlab.run()
150170
except (IOError, RuntimeError), e:
@@ -178,6 +198,9 @@ class SPMCommandInputSpec(BaseInterfaceInputSpec):
178198
mfile = traits.Bool(True, desc='Run m-code using m-file',
179199
usedefault=True)
180200
use_mcr = traits.Bool(desc='Run m-code using SPM MCR')
201+
use_v8struct = traits.Bool(True, min_ver='8', usedefault=True,
202+
desc=('Generate SPM8 and higher compatible jobs')
203+
)
181204

182205

183206
class SPMCommand(BaseInterface):
@@ -215,17 +238,25 @@ def _matlab_cmd_update(self):
215238
# and can be set only during init
216239
self.mlab = MatlabCommand(matlab_cmd=self.inputs.matlab_cmd,
217240
mfile=self.inputs.mfile,
218-
paths=self.inputs.paths,
219-
uses_mcr=self.inputs.use_mcr)
241+
paths=self.inputs.paths)
220242
self.mlab.inputs.script_file = 'pyscript_%s.m' % \
221243
self.__class__.__name__.split('.')[-1].lower()
222244
if isdefined(self.inputs.use_mcr) and self.inputs.use_mcr:
223245
self.mlab.inputs.nodesktop = Undefined
224246
self.mlab.inputs.nosplash = Undefined
247+
self.mlab.inputs.single_comp_thread = Undefined
248+
self.mlab.inputs.uses_mcr = True
249+
self.mlab.inputs.mfile = True
225250

226251
@property
227252
def version(self):
228-
return Info.version()
253+
version_dict = Info.version(matlab_cmd=self._matlab_cmd,
254+
paths=self._paths,
255+
use_mcr=self._use_mcr)
256+
if version_dict:
257+
return '.'.join((version_dict['name'].split('SPM')[-1],
258+
version_dict['release']))
259+
return version_dict
229260

230261
@property
231262
def jobtype(self):
@@ -300,9 +331,10 @@ def _reformat_dict_for_savemat(self, contents):
300331
301332
Examples
302333
--------
303-
>>> a = SPMCommand()._reformat_dict_for_savemat(dict(a=1,b=dict(c=2,d=3)))
304-
>>> print a
305-
[{'a': 1, 'b': [{'c': 2, 'd': 3}]}]
334+
>>> a = SPMCommand()._reformat_dict_for_savemat(dict(a=1,
335+
... b=dict(c=2, d=3)))
336+
>>> a == [{'a': 1, 'b': [{'c': 2, 'd': 3}]}]
337+
True
306338
307339
"""
308340
newdict = {}
@@ -401,48 +433,46 @@ def _make_matlab_command(self, contents, postscript=None):
401433
mscript = """
402434
%% Generated by nipype.interfaces.spm
403435
if isempty(which('spm')),
404-
throw(MException('SPMCheck:NotFound','SPM not in matlab path'));
436+
throw(MException('SPMCheck:NotFound', 'SPM not in matlab path'));
405437
end
406-
[name, ver] = spm('ver');
407-
fprintf('SPM version: %s Release: %s\\n',name, ver);
408-
fprintf('SPM path: %s\\n',which('spm'));
438+
[name, version] = spm('ver');
439+
fprintf('SPM version: %s Release: %s\\n',name, version);
440+
fprintf('SPM path: %s\\n', which('spm'));
409441
spm('Defaults','fMRI');
410442
411-
if strcmp(spm('ver'),'SPM8'), spm_jobman('initcfg');end\n
443+
if strcmp(name, 'SPM8') || strcmp(name, 'SPM12b'),
444+
spm_jobman('initcfg');
445+
spm_get_defaults('CmdLine', 1);
446+
end\n
412447
"""
413448
if self.mlab.inputs.mfile:
414-
if self.jobname in ['st', 'smooth', 'preproc', 'preproc8',
415-
'fmri_spec', 'fmri_est', 'factorial_design',
416-
'defs', 'dicom']:
417-
# parentheses
418-
mscript += self._generate_job('jobs{1}.%s{1}.%s(1)' %
449+
if isdefined(self.inputs.use_v8struct) and self.inputs.use_v8struct:
450+
mscript += self._generate_job('jobs{1}.spm.%s.%s' %
419451
(self.jobtype, self.jobname),
420452
contents[0])
421453
else:
422-
#curly brackets
423-
mscript += self._generate_job('jobs{1}.%s{1}.%s{1}' %
424-
(self.jobtype, self.jobname),
425-
contents[0])
454+
if self.jobname in ['st', 'smooth', 'preproc', 'preproc8',
455+
'fmri_spec', 'fmri_est', 'factorial_design',
456+
'defs']:
457+
# parentheses
458+
mscript += self._generate_job('jobs{1}.%s{1}.%s(1)' %
459+
(self.jobtype, self.jobname),
460+
contents[0])
461+
else:
462+
#curly brackets
463+
mscript += self._generate_job('jobs{1}.%s{1}.%s{1}' %
464+
(self.jobtype, self.jobname),
465+
contents[0])
426466
else:
427467
jobdef = {'jobs': [{self.jobtype:
428-
[{self.jobname:self.reformat_dict_for_savemat
429-
(contents[0])}]}]}
468+
[{self.jobname:
469+
self.reformat_dict_for_savemat(contents[0])}]
470+
}]}
430471
savemat(os.path.join(cwd, 'pyjobs_%s.mat' % self.jobname), jobdef)
431472
mscript += "load pyjobs_%s;\n\n" % self.jobname
432473
mscript += """
433-
if strcmp(spm('ver'),'SPM8'),
434-
jobs=spm_jobman('spm5tospm8',{jobs});
435-
end
436-
spm_jobman(\'run_nogui\',jobs);\n
474+
spm_jobman(\'run\', jobs);\n
437475
"""
438476
if postscript is not None:
439477
mscript += postscript
440478
return mscript
441-
442-
@property
443-
def version(self):
444-
version_dict = Info.version()
445-
if version_dict:
446-
return '.'.join((version_dict['name'].split('SPM')[-1],
447-
version_dict['release']))
448-
return version_dict

nipype/interfaces/spm/preprocess.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ class RealignInputSpec(SPMCommandInputSpec):
136136
wrap = traits.List(traits.Int(), minlen=3, maxlen=3,
137137
field='eoptions.wrap',
138138
desc='Check if interpolation should wrap in [x,y,z]')
139-
write_which = traits.ListInt([1, 1], field='roptions.which',
139+
write_which = traits.ListInt([2, 1], field='roptions.which',
140140
minlen=2, maxlen=2, usedefault=True,
141141
desc='determines which images to reslice')
142142
write_interp = traits.Range(low=0, high=7, field='roptions.interp',
@@ -146,7 +146,7 @@ class RealignInputSpec(SPMCommandInputSpec):
146146
desc='Check if interpolation should wrap in [x,y,z]')
147147
write_mask = traits.Bool(field='roptions.mask',
148148
desc='True/False mask output image')
149-
out_prefix = traits.String('r', field='prefix', usedefault=True,
149+
out_prefix = traits.String('r', field='roptions.prefix', usedefault=True,
150150
desc='realigned output prefix')
151151

152152

nipype/interfaces/spm/tests/test_base.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ class TestClass(spm.SPMCommand):
134134
dc = TestClass() # dc = derived_class
135135
dc.inputs.test_in = True
136136
out = dc._make_matlab_command(dc._parse_inputs())
137+
yield assert_equal, out.find('jobs{1}.spm.jobtype.jobname.testfield = 1;') > 0, 1
138+
dc.inputs.use_v8struct = False
139+
out = dc._make_matlab_command(dc._parse_inputs())
137140
yield assert_equal, out.find('jobs{1}.jobtype{1}.jobname{1}.testfield = 1;') > 0, 1
138141

139142
def test_make_matlab_command():
@@ -145,5 +148,8 @@ class TestClass(spm.SPMCommand):
145148
filelist, outdir, cwd = create_files_in_directory()
146149
contents = {'contents': [1, 2, 3, 4]}
147150
script = dc._make_matlab_command([contents])
151+
yield assert_true, 'jobs{1}.spm.jobtype.jobname.contents(3) = 3;' in script
152+
dc.inputs.use_v8struct = False
153+
script = dc._make_matlab_command([contents])
148154
yield assert_true, 'jobs{1}.jobtype{1}.jobname{1}.contents(3) = 3;' in script
149155
clean_directory(outdir, cwd)

0 commit comments

Comments
 (0)