Skip to content

Commit 5dbb5eb

Browse files
committed
Merge branch 'enh/mipav'
Conflicts: CHANGES
2 parents 25c8064 + dac452f commit 5dbb5eb

File tree

12 files changed

+984
-28
lines changed

12 files changed

+984
-28
lines changed

CHANGES

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
Next Release
22
============
33

4+
* ENH: Added experimental support for MIPAV algorithms thorugh JIST plugins
45
* ENH: New dipy interfaces: Denoise, Resample
56
* ENH: New Freesurfer interfaces: Tkregister2 (for conversion of fsl style matrices to freesurfer format),
67
MRIPretess
@@ -28,7 +29,8 @@ Next Release
2829
* ENH: New color mode for write_graph
2930
* ENH: You can now force MapNodes to be run serially
3031
* ENH: Added ANTS based openfmri workflow
31-
* ENH: MapNode now supports flattening nested lists
32+
* ENH: MapNode now supports flattening of nested lists
33+
* ENH: Support for headless mode using Xvfb
3234
* FIX: MRTrix tracking algorithms were ignoring mask parameters.
3335
* FIX: FNIRT registration pathway and associated OpenFMRI example script
3436
* FIX: spm12b compatibility for Model estimate

doc/devel/interface_specs.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,9 @@ If you used genfile:
404404

405405
And optionally:
406406

407+
* ``_redirect_x``: If set to True it will make Nipype start Xvfb before running the interface and redirect X output to it. This is useful for
408+
commandlines that spawn a graphical user interface.
409+
407410
* ``_format_arg(name, spec, value)``: For extra formatting of the input values before passing them to generic ``_parse_inputs()`` method.
408411

409412
For example this is the class definition for Flirt, minus the docstring::

doc/users/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
model_specification
3737
saving_workflows
3838
spmmcr
39+
mipav
3940

4041

4142

examples/smri_cbs_skullstripping.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import nipype.interfaces.io as nio # Data i/o
2+
import nipype.interfaces.utility as util # utility
3+
import nipype.pipeline.engine as pe # pypeline engine
4+
import nipype.interfaces.camino as camino
5+
import nipype.interfaces.fsl as fsl
6+
import nipype.interfaces.camino2trackvis as cam2trk
7+
import nipype.algorithms.misc as misc
8+
import os
9+
from nipype.interfaces.mipav.developer import JistIntensityMp2rageMasking, MedicAlgorithmSPECTRE2010
10+
11+
wf = pe.Workflow("skullstripping")
12+
13+
mask = pe.Node(JistIntensityMp2rageMasking(), name="masking")
14+
mask.inputs.inSecond = "/Users/filo/7t_trt/niftis/sub001/session_1/MP2RAGE_INV2.nii.gz"
15+
mask.inputs.inQuantitative = "/Users/filo/7t_trt/niftis/sub001/session_1/MP2RAGE_UNI.nii.gz"
16+
mask.inputs.inT1weighted = "/Users/filo/7t_trt/niftis/sub001/session_1/MP2RAGE_T1.nii.gz"
17+
mask.inputs.outMasked = True
18+
mask.inputs.outMasked2 = True
19+
mask.inputs.outSignal = True
20+
mask.inputs.outSignal2 = True
21+
22+
skullstrip = pe.Node(MedicAlgorithmSPECTRE2010(), name="skullstrip")
23+
skullstrip.inputs.outStripped = True
24+
skullstrip.inputs.xDefaultMem = 6000
25+
26+
wf.connect(mask, 'outMasked', skullstrip, 'inInput')
27+
wf.run()

nipype/interfaces/base.py

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
from ..utils.provenance import write_provenance
3939
from .. import config, logging, LooseVersion
4040
from .. import __version__
41+
import random, time, fnmatch
4142

4243
nipype_version = LooseVersion(__version__)
4344

@@ -46,6 +47,25 @@
4647

4748
__docformat__ = 'restructuredtext'
4849

50+
def _lock_files():
51+
tmpdir = '/tmp'
52+
pattern = '.X*-lock'
53+
names = fnmatch.filter(os.listdir(tmpdir), pattern)
54+
ls = [os.path.join(tmpdir, child) for child in names]
55+
ls = [p for p in ls if os.path.isfile(p)]
56+
return ls
57+
58+
def _search_for_free_display():
59+
ls = [int(x.split('X')[1].split('-')[0]) for x in _lock_files()]
60+
min_display_num = 1000
61+
if len(ls):
62+
display_num = max(min_display_num, max(ls) + 1)
63+
else:
64+
display_num = min_display_num
65+
random.seed()
66+
display_num += random.randint(0, 100)
67+
return display_num
68+
4969

5070
def load_template(name):
5171
"""Load a template from the script_templates directory
@@ -701,6 +721,7 @@ class BaseInterface(Interface):
701721
input_spec = BaseInterfaceInputSpec
702722
_version = None
703723
_additional_metadata = []
724+
_redirect_x = False
704725

705726
def __init__(self, **inputs):
706727
if not self.input_spec:
@@ -956,7 +977,30 @@ def run(self, **inputs):
956977
hostname=getfqdn(),
957978
version=self.version)
958979
try:
980+
if self._redirect_x:
981+
exist_val, _ = self._exists_in_path('Xvfb',
982+
runtime.environ)
983+
if not exist_val:
984+
raise IOError("Xvfb could not be found on host %s" %
985+
(runtime.hostname))
986+
else:
987+
vdisplay_num = _search_for_free_display()
988+
xvfb_cmd = ['Xvfb', ':%d' % vdisplay_num]
989+
xvfb_proc = subprocess.Popen(xvfb_cmd,
990+
stdout=open(os.devnull),
991+
stderr=open(os.devnull))
992+
time.sleep(0.2) # give Xvfb time to start
993+
if xvfb_proc.poll() is not None:
994+
raise Exception('Error: Xvfb did not start')
995+
old_displaynum = os.environ['DISPLAY']
996+
runtime.environ['DISPLAY'] = ':%s' % vdisplay_num
997+
959998
runtime = self._run_interface(runtime)
999+
1000+
if self._redirect_x:
1001+
xvfb_proc.kill()
1002+
xvfb_proc.wait()
1003+
9601004
outputs = self.aggregate_outputs(runtime)
9611005
runtime.endTime = dt.isoformat(dt.utcnow())
9621006
timediff = parseutc(runtime.endTime) - parseutc(runtime.startTime)
@@ -1344,11 +1388,12 @@ def help(cls, returnhelp=False):
13441388

13451389
def _get_environ(self):
13461390
out_environ = {}
1347-
try:
1348-
display_var = config.get('execution', 'display_variable')
1349-
out_environ = {'DISPLAY': display_var}
1350-
except NoOptionError:
1351-
pass
1391+
if not self._redirect_x:
1392+
try:
1393+
display_var = config.get('execution', 'display_variable')
1394+
out_environ = {'DISPLAY': display_var}
1395+
except NoOptionError:
1396+
pass
13521397
iflogger.debug(out_environ)
13531398
if isdefined(self.inputs.environ):
13541399
out_environ.update(self.inputs.environ)

nipype/interfaces/mipav/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from developer import JistLaminarVolumetricLayering, JistBrainMgdmSegmentation, JistLaminarProfileGeometry, JistLaminarProfileCalculator, MedicAlgorithmN3, JistLaminarROIAveraging, MedicAlgorithmLesionToads, JistBrainMp2rageSkullStripping, JistCortexSurfaceMeshInflation, RandomVol, MedicAlgorithmImageCalculator, JistBrainMp2rageDuraEstimation, JistLaminarProfileSampling, MedicAlgorithmMipavReorient, MedicAlgorithmSPECTRE2010, JistBrainPartialVolumeFilter, JistIntensityMp2rageMasking, MedicAlgorithmThresholdToBinaryMask

0 commit comments

Comments
 (0)