Skip to content

Commit 4fdce5c

Browse files
committed
several fixups
- [x] Add `num_threads` as a property synchronized with `inputs.num_threads` in afni interfaces - [x] Add syncrhonization between `Node.n_procs` and `Interface.inputs.num_threads` - [x] Minor documentation fixes of the old profiler callback-log.
1 parent ef097a6 commit 4fdce5c

File tree

3 files changed

+60
-36
lines changed

3 files changed

+60
-36
lines changed

nipype/interfaces/afni/base.py

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ def _run_interface(self, runtime):
130130

131131

132132
class AFNICommandInputSpec(CommandLineInputSpec):
133+
num_threads = traits.Int(1, usedefault=True, nohash=True,
134+
desc='set number of threads')
133135
outputtype = traits.Enum('AFNI', list(Info.ftypes.keys()),
134136
desc='AFNI output filetype')
135137
out_file = File(name_template="%s_afni", desc='output image file name',
@@ -141,6 +143,7 @@ class AFNICommandOutputSpec(TraitedSpec):
141143
out_file = File(desc='output file',
142144
exists=True)
143145

146+
144147
class AFNICommand(AFNICommandBase):
145148
"""Shared options for several AFNI commands """
146149
input_spec = AFNICommandInputSpec
@@ -172,9 +175,33 @@ class AFNICommand(AFNICommandBase):
172175
'tags': ['implementation'],
173176
}]
174177

178+
@property
179+
def num_threads(self):
180+
return self.inputs.num_threads
181+
182+
@num_threads.setter
183+
def num_threads(self, value):
184+
self.inputs.num_threads = value
185+
186+
@classmethod
187+
def set_default_output_type(cls, outputtype):
188+
"""Set the default output type for AFNI classes.
189+
190+
This method is used to set the default output type for all afni
191+
subclasses. However, setting this will not update the output
192+
type for any existing instances. For these, assign the
193+
<instance>.inputs.outputtype.
194+
"""
195+
196+
if outputtype in Info.ftypes:
197+
cls._outputtype = outputtype
198+
else:
199+
raise AttributeError('Invalid AFNI outputtype: %s' % outputtype)
200+
175201
def __init__(self, **inputs):
176202
super(AFNICommand, self).__init__(**inputs)
177203
self.inputs.on_trait_change(self._output_update, 'outputtype')
204+
self.inputs.on_trait_change(self._nthreads_update, 'num_threads')
178205

179206
if self._outputtype is None:
180207
self._outputtype = Info.outputtype()
@@ -184,11 +211,9 @@ def __init__(self, **inputs):
184211
else:
185212
self._output_update()
186213

187-
def _run_interface(self, runtime):
188-
# Update num threads estimate from OMP_NUM_THREADS env var
189-
# Default to 1 if not set
190-
self.inputs.environ['OMP_NUM_THREADS'] = str(self.num_threads)
191-
return super(AFNICommand, self)._run_interface(runtime)
214+
def _nthreads_update(self):
215+
"""Update environment with new number of threads"""
216+
self.inputs.environ['OMP_NUM_THREADS'] = '%d' % self.inputs.num_threads
192217

193218
def _output_update(self):
194219
""" i think? updates class private attribute based on instance input
@@ -197,21 +222,6 @@ def _output_update(self):
197222
"""
198223
self._outputtype = self.inputs.outputtype
199224

200-
@classmethod
201-
def set_default_output_type(cls, outputtype):
202-
"""Set the default output type for AFNI classes.
203-
204-
This method is used to set the default output type for all afni
205-
subclasses. However, setting this will not update the output
206-
type for any existing instances. For these, assign the
207-
<instance>.inputs.outputtype.
208-
"""
209-
210-
if outputtype in Info.ftypes:
211-
cls._outputtype = outputtype
212-
else:
213-
raise AttributeError('Invalid AFNI outputtype: %s' % outputtype)
214-
215225
def _overload_extension(self, value, name=None):
216226
path, base, _ = split_filename(value)
217227
return os.path.join(path, base + Info.output_type_to_ext(self.inputs.outputtype))
@@ -274,6 +284,7 @@ def _gen_fname(self, basename, cwd=None, suffix=None, change_ext=True,
274284
use_ext=False, newpath=cwd)
275285
return fname
276286

287+
277288
def no_afni():
278289
""" Checks if AFNI is available """
279290
if Info.version() is None:
@@ -285,8 +296,9 @@ class AFNIPythonCommandInputSpec(CommandLineInputSpec):
285296
outputtype = traits.Enum('AFNI', list(Info.ftypes.keys()),
286297
desc='AFNI output filetype')
287298
py27_path = traits.Either('python2', File(exists=True),
288-
usedefault=True,
289-
default='python2')
299+
usedefault=True,
300+
default='python2')
301+
290302

291303
class AFNIPythonCommand(AFNICommand):
292304
@property

nipype/pipeline/engine/nodes.py

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class Node(EngineBase):
7979

8080
def __init__(self, interface, name, iterables=None, itersource=None,
8181
synchronize=False, overwrite=None, needed_outputs=None,
82-
run_without_submitting=False, n_procs=1, mem_gb=0.20,
82+
run_without_submitting=False, n_procs=None, mem_gb=0.20,
8383
**kwargs):
8484
"""
8585
Parameters
@@ -153,12 +153,15 @@ def __init__(self, interface, name, iterables=None, itersource=None,
153153
if 'base_dir' in kwargs:
154154
base_dir = kwargs['base_dir']
155155
super(Node, self).__init__(name, base_dir)
156+
157+
# Make sure an interface is set, and that it is an Interface
156158
if interface is None:
157159
raise IOError('Interface must be provided')
158160
if not isinstance(interface, Interface):
159161
raise IOError('interface must be an instance of an Interface')
160162
self._interface = interface
161163
self.name = name
164+
162165
self._result = None
163166
self.iterables = iterables
164167
self.synchronize = synchronize
@@ -170,8 +173,10 @@ def __init__(self, interface, name, iterables=None, itersource=None,
170173
self.needed_outputs = []
171174
self.plugin_args = {}
172175

173-
self._n_procs = n_procs
174176
self._mem_gb = mem_gb
177+
self._n_procs = n_procs
178+
if hasattr(self.inputs, 'num_threads') and self._n_procs is not None:
179+
self.inputs.num_threads = self._n_procs
175180

176181
if needed_outputs:
177182
self.needed_outputs = sorted(needed_outputs)
@@ -213,16 +218,22 @@ def mem_gb(self):
213218

214219
@property
215220
def n_procs(self):
216-
"""Get estimated number of processes"""
217-
if hasattr(self._interface, 'num_threads'):
218-
self._n_procs = self._interface.num_threads
219-
logger.warning('Setting "num_threads" on Interfaces has been '
220-
'deprecated as of nipype 1.0, please use Node.n_procs')
221-
222-
if hasattr(self._interface.inputs, 'num_threads') and isdefined(
223-
self._interface.inputs.num_threads):
224-
self._n_procs = self._interface.inputs.num_threads
225-
return self._n_procs
221+
"""Get the estimated number of processes/threads"""
222+
if self._n_procs is not None:
223+
return self._n_procs
224+
elif hasattr(self.inputs, 'num_threads') and isdefined(self.inputs.num_threads):
225+
return self.inputs.num_threads
226+
else:
227+
return 1
228+
229+
@n_procs.setter
230+
def n_procs(self, value):
231+
"""Set an estimated number of processes/threads"""
232+
self._n_procs = value
233+
234+
# Overwrite interface's dynamic input of num_threads
235+
if hasattr(self._interface.inputs, 'num_threads'):
236+
self._interface.inputs.num_threads = self._n_procs
226237

227238
def output_dir(self):
228239
"""Return the location of the output directory for the node"""

nipype/utils/draw_gantt_chart.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
# -*- coding: utf-8 -*-
22
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
33
# vi: set ft=python sts=4 ts=4 sw=4 et:
4-
"""Module to draw an html gantt chart from logfile produced by
5-
callback_log.log_nodes_cb()
4+
"""
5+
Module to draw an html gantt chart from logfile produced by
6+
``nipype.utils.profiler.log_nodes_cb()``
67
"""
78
from __future__ import print_function, division, unicode_literals, absolute_import
89

0 commit comments

Comments
 (0)