Skip to content

Commit 6e4af1f

Browse files
committed
dipy workflow to nipype
1 parent 617a2a9 commit 6e4af1f

File tree

4 files changed

+178
-3
lines changed

4 files changed

+178
-3
lines changed

nipype/interfaces/dipy/base.py

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
import numpy as np
88
from ... import logging
99
from ..base import (traits, File, isdefined, LibraryBaseInterface,
10-
BaseInterfaceInputSpec)
10+
BaseInterfaceInputSpec, TraitedSpec)
1111

1212
HAVE_DIPY = True
1313
try:
1414
import dipy
15+
from dipy.workflows.base import IntrospectiveArgumentParser
1516
except ImportError:
1617
HAVE_DIPY = False
1718

@@ -75,3 +76,123 @@ def _gen_filename(self, name, ext=None):
7576
ext = fext
7677

7778
return out_prefix + '_' + name + ext
79+
80+
81+
def convert_to_traits_type(dipy_type, is_file=False):
82+
"""Convert DIPY type to Traits type."""
83+
dipy_type = dipy_type.lower()
84+
is_mandatory = bool("optional" not in dipy_type)
85+
if "variable" in dipy_type and "string" in dipy_type:
86+
return traits.ListStr, is_mandatory
87+
elif "variable" in dipy_type and "int" in dipy_type:
88+
return traits.ListInt, is_mandatory
89+
elif "variable" in dipy_type and "float" in dipy_type:
90+
return traits.ListFloat, is_mandatory
91+
elif "variable" in dipy_type and "bool" in dipy_type:
92+
return traits.ListBool, is_mandatory
93+
elif "variable" in dipy_type and "complex" in dipy_type:
94+
return traits.ListComplex, is_mandatory
95+
elif "string" in dipy_type and not is_file:
96+
return traits.Str, is_mandatory
97+
elif "string" in dipy_type and is_file:
98+
return traits.File, is_mandatory
99+
elif "int" in dipy_type:
100+
return traits.Int, is_mandatory
101+
elif "float" in dipy_type:
102+
return traits.Float, is_mandatory
103+
elif "bool" in dipy_type:
104+
return traits.Bool, is_mandatory
105+
elif "complex" in dipy_type:
106+
return traits.Complex, is_mandatory
107+
else:
108+
msg = "Error during convert_to_traits_type({0}).".format(dipy_type) + \
109+
"Unknown DIPY type."
110+
raise IOError(msg)
111+
112+
113+
def create_interface_specs(class_name, params=None, BaseClass=TraitedSpec):
114+
"""Create IN/Out interface specifications dynamically.
115+
116+
Parameters
117+
----------
118+
class_name: str
119+
The future class name(e.g, (MyClassInSpec))
120+
params: list of tuple
121+
dipy argument list
122+
BaseClass: TraitedSpec object
123+
parent class
124+
125+
Returns
126+
-------
127+
newclass: object
128+
new nipype interface specification class
129+
130+
"""
131+
attr = {}
132+
if params is not None:
133+
for name, dipy_type, desc in params:
134+
is_file = bool("files" in name or "out_" in name)
135+
traits_type, is_mandatory = convert_to_traits_type(dipy_type,
136+
is_file)
137+
# print(name, dipy_type, desc, is_file, traits_type, is_mandatory)
138+
if isinstance(BaseClass, BaseInterfaceInputSpec):
139+
attr[name] = traits_type(desc=desc[-1], mandatory=is_mandatory)
140+
else:
141+
attr[name] = traits_type(desc=desc[-1], exists=True)
142+
143+
newclass = type(class_name, (BaseClass, ), attr)
144+
return newclass
145+
146+
147+
def dipy_to_nipype_interface(cls_name, dipy_flow, BaseClass=DipyBaseInterface):
148+
"""Construct a class in order to respect nipype interface specifications.
149+
150+
This convenient class factory convert a DIPY Workflow to a nipype
151+
interface.
152+
153+
Parameters
154+
----------
155+
cls_name: string
156+
new class name
157+
dipy_flow: Workflow class type.
158+
It should be any children class of `dipy.workflows.workflow.Worflow`
159+
BaseClass: object
160+
nipype instance object
161+
162+
Returns
163+
-------
164+
newclass: object
165+
new nipype interface specification class
166+
167+
"""
168+
parser = IntrospectiveArgumentParser()
169+
parser.add_workflow(dipy_flow())
170+
input_parameters = parser.positional_parameters + parser.optional_parameters
171+
172+
input_spec = create_interface_specs("{}InputSpec".format(cls_name),
173+
input_parameters,
174+
BaseClass=BaseInterfaceInputSpec)
175+
176+
output_spec = create_interface_specs("{}OutputSpec".format(cls_name),
177+
parser.output_parameters,
178+
BaseClass=TraitedSpec)
179+
180+
def _run_interface(self, runtime):
181+
flow = dipy_flow()
182+
args = self.inputs.get()
183+
flow.run(**args)
184+
185+
def _list_outputs(self):
186+
outputs = self._outputs().get()
187+
out_dir = outputs.get("out_dir", ".")
188+
for key, values in outputs.items():
189+
outputs[key] = op.join(out_dir, values)
190+
191+
return outputs
192+
193+
newclass = type(cls_name, (BaseClass, ),
194+
{"input_spec": input_spec,
195+
"output_spec": output_spec,
196+
"_run_interface": _run_interface,
197+
"_list_outputs:": _list_outputs})
198+
return newclass

nipype/interfaces/dipy/reconstruction.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,30 @@
1313

1414
import numpy as np
1515
import nibabel as nb
16+
from distutils.version import LooseVersion
1617

1718
from ... import logging
1819
from ..base import TraitedSpec, File, traits, isdefined
19-
from .base import DipyDiffusionInterface, DipyBaseInterfaceInputSpec
20+
from .base import (DipyDiffusionInterface, DipyBaseInterfaceInputSpec,
21+
HAVE_DIPY, dipy_version, dipy_to_nipype_interface)
22+
2023

2124
IFLOGGER = logging.getLogger('nipype.interface')
2225

26+
if HAVE_DIPY and LooseVersion(dipy_version()) >= LooseVersion('0.15'):
27+
from dipy.workflows.reconst import (ReconstDkiFlow, ReconstCSAFlow,
28+
ReconstCSDFlow, ReconstMAPMRIFlow,
29+
ReconstDtiFlow)
30+
import ipdb; ipdb.set_trace()
31+
DKIModel = dipy_to_nipype_interface("DKIModel", ReconstDkiFlow)
32+
MapmriModel = dipy_to_nipype_interface("MapmriModel", ReconstMAPMRIFlow)
33+
DTIModel = dipy_to_nipype_interface("DTIModel", ReconstDtiFlow)
34+
CSAModel = dipy_to_nipype_interface("CSAModel", ReconstCSAFlow)
35+
CSDModel = dipy_to_nipype_interface("CSDModel", ReconstCSDFlow)
36+
else:
37+
IFLOGGER.info("We advise you to upgrade DIPY version. This upgrade will"
38+
" activate DKIModel, MapmriModel, DTIModel, CSAModel.")
39+
2340

2441
class RESTOREInputSpec(DipyBaseInterfaceInputSpec):
2542
in_mask = File(exists=True, desc=('input mask in which compute tensors'))
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
from distutils.version import LooseVersion
3+
from ... import logging
4+
from .base import HAVE_DIPY, dipy_version, dipy_to_nipype_interface
5+
6+
IFLOGGER = logging.getLogger('nipype.interface')
7+
8+
if HAVE_DIPY and LooseVersion(dipy_version()) >= LooseVersion('0.15'):
9+
10+
from dipy.workflows.align import ResliceFlow, SlrWithQbxFlow
11+
12+
Reslice = dipy_to_nipype_interface("Reslice", ResliceFlow)
13+
StreamlineRegistration = dipy_to_nipype_interface("StreamlineRegistration",
14+
SlrWithQbxFlow)
15+
16+
else:
17+
IFLOGGER.info("We advise you to upgrade DIPY version. This upgrade will"
18+
" activate Reslice, StreamlineRegistration.")

nipype/interfaces/dipy/tracks.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,33 @@
66
import numpy as np
77
import nibabel as nb
88
import nibabel.trackvis as nbt
9+
from distutils.version import LooseVersion
910

1011
from ... import logging
1112
from ..base import (TraitedSpec, BaseInterfaceInputSpec, File, isdefined,
1213
traits)
13-
from .base import DipyBaseInterface
14+
from .base import (DipyBaseInterface, HAVE_DIPY, dipy_version,
15+
dipy_to_nipype_interface)
16+
1417
IFLOGGER = logging.getLogger('nipype.interface')
1518

1619

20+
if HAVE_DIPY and LooseVersion(dipy_version()) >= LooseVersion('0.15'):
21+
22+
from dipy.workflows.segment import RecoBundlesFlow, LabelsBundlesFlow
23+
from dipy.workflows.tracking import DetTrackPAMFlow
24+
25+
RecoBundles = dipy_to_nipype_interface("RecoBundles", RecoBundlesFlow)
26+
LabelsBundles = dipy_to_nipype_interface("LabelsBundles",
27+
LabelsBundlesFlow)
28+
DeterministicTracking = dipy_to_nipype_interface("DeterministicTracking",
29+
DetTrackPAMFlow)
30+
31+
else:
32+
IFLOGGER.info("We advise you to upgrade DIPY version. This upgrade will"
33+
" activate RecoBundles, LabelsBundles, DetTrackPAMFlow.")
34+
35+
1736
class TrackDensityMapInputSpec(BaseInterfaceInputSpec):
1837
in_file = File(
1938
exists=True, mandatory=True, desc='The input TrackVis track file')

0 commit comments

Comments
 (0)