Skip to content

Commit dc1a4cd

Browse files
committed
tested new XFibres. new parallel workflow
1 parent 449452f commit dc1a4cd

File tree

6 files changed

+198
-80
lines changed

6 files changed

+198
-80
lines changed

nipype/interfaces/fsl/base.py

Lines changed: 34 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ class FSLXCommandInputSpec(FSLCommandInputSpec):
255255
bvals = File(exists=True, argstr='--bvals=%s', mandatory=True,
256256
desc='b values file')
257257

258-
logdir = Directory('logdir', argstr='--logdir=%s', usedefault=True)
258+
logdir = Directory('.', argstr='--logdir=%s', usedefault=True)
259259
n_fibres = traits.Range(low=1, argstr='--nfibres=%d', desc=('Maximum '
260260
'number of fibres to fit in each voxel'))
261261
model = traits.Enum(1, 2, argstr='--model=%d',
@@ -311,34 +311,22 @@ class FSLXCommandInputSpec(FSLCommandInputSpec):
311311

312312

313313
class FSLXCommandOutputSpec(TraitedSpec):
314-
merged_thsamples = OutputMultiPath(File(), desc=('Samples from '
315-
'the distribution on theta'))
316-
merged_phsamples = OutputMultiPath(File(), desc=('Samples from '
317-
'the distribution on phi'))
318-
merged_fsamples = OutputMultiPath(File(),
319-
desc=('Samples from the distribution on '
320-
'anisotropic volume fraction.'))
321-
322-
mean_thsamples = OutputMultiPath(File(), desc=('Mean of '
323-
'distribution on theta'))
324-
mean_phsamples = OutputMultiPath(File(), desc=('Mean of '
325-
'distribution on phi'))
314+
dsamples = File(desc=('Samples from the distribution on diffusivity d'))
315+
d_stdsamples = File(desc=('Std of samples from the distribution d'))
316+
dyads = OutputMultiPath(File(), desc=('Mean of PDD distribution'
317+
' in vector form.'))
318+
fsamples = OutputMultiPath(File(), desc=('Samples from the '
319+
'distribution on f anisotropy'))
320+
mean_dsamples = File(desc='Mean of distribution on diffusivity d')
321+
mean_d_stdsamples = File(desc='Mean of distribution on diffusivity d')
326322
mean_fsamples = OutputMultiPath(File(), desc=('Mean of '
327323
'distribution on f anisotropy'))
328-
329-
mean_dsamples = File(desc='Mean of distribution on '
330-
'diffusivity d')
331324
mean_S0samples = File(desc='Mean of distribution on T2w'
332325
'baseline signal intensity S0')
333326
mean_tausamples = File(desc='Mean of distribution on '
334327
'tau samples (only with rician noise)')
335-
336-
dyads = OutputMultiPath(File(), desc=('Mean of PDD distribution'
337-
' in vector form.'))
338-
dyads_disp = OutputMultiPath(File(), desc=('Uncertainty on the '
339-
' estimated fiber orientation'))
340-
fsamples = OutputMultiPath(File(), desc=('Samples from the '
341-
'distribution on anisotropic volume fraction'))
328+
phsamples = OutputMultiPath(File(), desc=('phi samples, per fiber'))
329+
thsamples = OutputMultiPath(File(), desc=('theta samples, per fiber'))
342330

343331

344332
class FSLXCommand(FSLCommand):
@@ -359,45 +347,38 @@ def _list_outputs(self):
359347
outputs = self.output_spec().get()
360348
out_dir = self._out_dir
361349

362-
for k in outputs.keys():
363-
if k not in ('outputtype', 'environ', 'args', 'bpx_out_directory',
364-
'xfms_directory', 'mean_dsamples', 'mean_S0samples',
365-
'mean_tausamples'):
366-
outputs[k] = []
350+
if isdefined(self.inputs.logdir):
351+
out_dir = os.path.abspath(self.inputs.logdir)
352+
else:
353+
out_dir = os.path.abspath('logdir')
354+
355+
multi_out = ['dyads', 'fsamples', 'mean_fsamples',
356+
'phsamples', 'thsamples']
357+
single_out = ['dsamples', 'd_stdsamples', 'mean_dsamples',
358+
'mean_S0samples', 'mean_d_stdsamples']
367359

368-
outputs['mean_dsamples'] = self._gen_fname('mean_dsamples',
369-
cwd=out_dir)
370-
outputs['mean_S0samples'] = self._gen_fname('mean_S0samples',
371-
cwd=out_dir)
360+
for k in single_out:
361+
outputs[k] = self._gen_fname(k, cwd=out_dir)
372362

373363
if isdefined(self.inputs.rician) and self.inputs.rician:
374364
outputs['mean_tausamples'] = self._gen_fname('mean_tausamples',
375365
cwd=out_dir)
376366

367+
for k in multi_out:
368+
outputs[k] = []
369+
377370
for i in xrange(1, self.inputs.n_fibres + 1):
378-
outputs['merged_thsamples'].append(self._gen_fname(('merged_th%d'
379-
'samples') % i,
380-
cwd=out_dir))
381-
outputs['merged_phsamples'].append(self._gen_fname(('merged_ph%d'
382-
'samples') % i,
383-
cwd=out_dir))
384-
outputs['merged_fsamples'].append(self._gen_fname(('merged_f%d'
385-
'samples') % i,
386-
cwd=out_dir))
387-
388-
outputs['mean_thsamples'].append(self._gen_fname(('mean_th%d'
389-
'samples') % i,
390-
cwd=out_dir))
391-
outputs['mean_phsamples'].append(self._gen_fname(('mean_ph%d'
392-
'samples') % i,
393-
cwd=out_dir))
394-
outputs['mean_fsamples'].append(self._gen_fname(('mean_f%d'
395-
'samples') % i,
396-
cwd=out_dir))
397371
outputs['dyads'].append(self._gen_fname('dyads%d' % i,
398372
cwd=out_dir))
399-
outputs['dyads_disp'].append(self._gen_fname(('dyads%d'
400-
'_dispersion') % i, cwd=out_dir))
373+
outputs['fsamples'].append(self._gen_fname('f%dsamples' % i,
374+
cwd=out_dir))
375+
outputs['mean_fsamples'].append(self._gen_fname(('mean_f%d'
376+
'samples') % i, cwd=out_dir))
377+
outputs['phsamples'].append(self._gen_fname('ph%dsamples' % i,
378+
cwd=out_dir))
379+
outputs['thsamples'].append(self._gen_fname('th%dsamples' % i,
380+
cwd=out_dir))
381+
401382
return outputs
402383

403384

nipype/interfaces/fsl/dti.py

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,23 @@ class BEDPOSTXInputSpec(FSLXCommandInputSpec):
107107
'nonlinearities, default off'))
108108

109109

110+
class BEDPOSTXOutputSpec(FSLXCommandOutputSpec):
111+
mean_thsamples = OutputMultiPath(File(), desc=('Mean of '
112+
'distribution on theta'))
113+
mean_phsamples = OutputMultiPath(File(), desc=('Mean of '
114+
'distribution on phi'))
115+
116+
merged_thsamples = OutputMultiPath(File(), desc=('Samples from '
117+
'the distribution on theta'))
118+
merged_phsamples = OutputMultiPath(File(), desc=('Samples from '
119+
'the distribution on phi'))
120+
merged_fsamples = OutputMultiPath(File(),
121+
desc=('Samples from the distribution on '
122+
'anisotropic volume fraction.'))
123+
dyads_disp = OutputMultiPath(File(), desc=('Uncertainty on the '
124+
' estimated fiber orientation'))
125+
126+
110127
class BEDPOSTX(FSLXCommand):
111128
"""
112129
BEDPOSTX stands for Bayesian Estimation of Diffusion Parameters Obtained
@@ -130,13 +147,13 @@ class BEDPOSTX(FSLXCommand):
130147
... mask='mask.nii', n_fibres=1)
131148
>>> bedp.cmdline
132149
'bedpostx . --bvals=bvals --bvecs=bvecs --data=diffusion.nii \
133-
--forcedir --logdir=logdir --mask=mask.nii --nfibres=1'
150+
--forcedir --logdir=. --mask=mask.nii --nfibres=1'
134151
135152
"""
136153

137154
_cmd = 'bedpostx'
138155
input_spec = BEDPOSTXInputSpec
139-
output_spec = FSLXCommandOutputSpec
156+
output_spec = BEDPOSTXOutputSpec
140157
_can_resume = True
141158

142159
def _run_interface(self, runtime):
@@ -164,6 +181,41 @@ def _run_interface(self, runtime):
164181

165182
return super(BEDPOSTX, self)._run_interface(runtime)
166183

184+
def _list_outputs(self):
185+
outputs = self.output_spec().get()
186+
out_dir = self._out_dir
187+
188+
post_fields = ['merged_thsamples', 'merged_phsamples',
189+
'merged_fsamples', 'dyads_disp']
190+
for k in post_fields:
191+
outputs[k] = []
192+
193+
for i in xrange(1, self.inputs.n_fibres + 1):
194+
outputs['merged_thsamples'].append(self._gen_fname(('merged_th%d'
195+
'samples') % i,
196+
cwd=out_dir))
197+
outputs['merged_phsamples'].append(self._gen_fname(('merged_ph%d'
198+
'samples') % i,
199+
cwd=out_dir))
200+
outputs['merged_fsamples'].append(self._gen_fname(('merged_f%d'
201+
'samples') % i,
202+
cwd=out_dir))
203+
outputs['mean_thsamples'].append(self._gen_fname(('mean_th%d'
204+
'samples') % i,
205+
cwd=out_dir))
206+
outputs['mean_phsamples'].append(self._gen_fname(('mean_ph%d'
207+
'samples') % i,
208+
cwd=out_dir))
209+
outputs['dyads_disp'].append(self._gen_fname(('dyads%d'
210+
'_dispersion') % i, cwd=out_dir))
211+
212+
super_out = super(BEDPOSTX, self)._list_outputs()
213+
214+
for k, v in super_out.iteritems():
215+
outputs[k] = v
216+
217+
return outputs
218+
167219

168220
class XFibresInputSpec(FSLXCommandInputSpec):
169221
gradnonlin = File(exists=True, argstr='--gradnonlin=%s',

nipype/interfaces/fsl/tests/test_auto_BEDPOSTX.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,13 @@ def test_BEDPOSTX_inputs():
8989
yield assert_equal, getattr(inputs.traits()[key], metakey), value
9090

9191
def test_BEDPOSTX_outputs():
92-
output_map = dict(dyads=dict(),
92+
output_map = dict(d_stdsamples=dict(),
93+
dsamples=dict(),
94+
dyads=dict(),
9395
dyads_disp=dict(),
9496
fsamples=dict(),
9597
mean_S0samples=dict(),
98+
mean_d_stdsamples=dict(),
9699
mean_dsamples=dict(),
97100
mean_fsamples=dict(),
98101
mean_phsamples=dict(),
@@ -101,6 +104,8 @@ def test_BEDPOSTX_outputs():
101104
merged_fsamples=dict(),
102105
merged_phsamples=dict(),
103106
merged_thsamples=dict(),
107+
phsamples=dict(),
108+
thsamples=dict(),
104109
)
105110
outputs = BEDPOSTX.output_spec()
106111

nipype/interfaces/fsl/tests/test_auto_FSLXCommand.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,18 +82,17 @@ def test_FSLXCommand_inputs():
8282
yield assert_equal, getattr(inputs.traits()[key], metakey), value
8383

8484
def test_FSLXCommand_outputs():
85-
output_map = dict(dyads=dict(),
86-
dyads_disp=dict(),
85+
output_map = dict(d_stdsamples=dict(),
86+
dsamples=dict(),
87+
dyads=dict(),
8788
fsamples=dict(),
8889
mean_S0samples=dict(),
90+
mean_d_stdsamples=dict(),
8991
mean_dsamples=dict(),
9092
mean_fsamples=dict(),
91-
mean_phsamples=dict(),
9293
mean_tausamples=dict(),
93-
mean_thsamples=dict(),
94-
merged_fsamples=dict(),
95-
merged_phsamples=dict(),
96-
merged_thsamples=dict(),
94+
phsamples=dict(),
95+
thsamples=dict(),
9796
)
9897
outputs = FSLXCommand.output_spec()
9998

nipype/interfaces/fsl/tests/test_auto_XFibres.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -84,18 +84,17 @@ def test_XFibres_inputs():
8484
yield assert_equal, getattr(inputs.traits()[key], metakey), value
8585

8686
def test_XFibres_outputs():
87-
output_map = dict(dyads=dict(),
88-
dyads_disp=dict(),
87+
output_map = dict(d_stdsamples=dict(),
88+
dsamples=dict(),
89+
dyads=dict(),
8990
fsamples=dict(),
9091
mean_S0samples=dict(),
92+
mean_d_stdsamples=dict(),
9193
mean_dsamples=dict(),
9294
mean_fsamples=dict(),
93-
mean_phsamples=dict(),
9495
mean_tausamples=dict(),
95-
mean_thsamples=dict(),
96-
merged_fsamples=dict(),
97-
merged_phsamples=dict(),
98-
merged_thsamples=dict(),
96+
phsamples=dict(),
97+
thsamples=dict(),
9998
)
10099
outputs = XFibres.output_spec()
101100

nipype/workflows/dmri/fsl/dti.py

Lines changed: 92 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,22 +59,104 @@ def create_bedpostx_pipeline(name='bedpostx', params={}):
5959
xfibres = pe.MapNode(xfib_if, name='xfibres',
6060
iterfield=['dwi', 'mask'])
6161

62-
out_fields = xfib_if.output_spec().get().keys()
62+
make_dyads = pe.MapNode(fsl.MakeDyadicVectors(), name="make_dyads",
63+
iterfield=['theta_vol', 'phi_vol'])
64+
out_fields = ['dyads', 'dyads_disp',
65+
'thsamples', 'phsamples', 'fsamples',
66+
'mean_thsamples', 'mean_phsamples', 'mean_fsamples']
6367

6468
outputnode = pe.Node(niu.IdentityInterface(fields=out_fields),
6569
name='outputnode')
6670

6771
wf = pe.Workflow(name=name)
6872
wf.connect([
69-
(inputnode, slice_dwi, [('dwi', 'in_file')]),
70-
(inputnode, slice_msk, [('mask', 'in_file')]),
71-
(slice_dwi, mask_dwi, [('out_files', 'in_file')]),
72-
(slice_msk, mask_dwi, [('out_files', 'in_file2')]),
73-
(slice_dwi, xfibres, [('out_files', 'dwi')]),
74-
(mask_dwi, xfibres, [('out_file', 'mask')]),
75-
(inputnode, xfibres, [('bvecs', 'bvecs'),
76-
('bvals', 'bvals')]),
77-
(xfibres, outputnode, [((f, transpose), f) for f in out_fields])
73+
(inputnode, slice_dwi, [('dwi', 'in_file')]),
74+
(inputnode, slice_msk, [('mask', 'in_file')]),
75+
(slice_dwi, mask_dwi, [('out_files', 'in_file')]),
76+
(slice_msk, mask_dwi, [('out_files', 'in_file2')]),
77+
(slice_dwi, xfibres, [('out_files', 'dwi')]),
78+
(mask_dwi, xfibres, [('out_file', 'mask')]),
79+
(inputnode, xfibres, [('bvecs', 'bvecs'),
80+
('bvals', 'bvals')]),
81+
(inputnode, make_dyads, [('mask', 'mask')])
7882
])
7983

84+
mms = {}
85+
for k in ['thsamples', 'phsamples', 'fsamples']:
86+
mms[k] = merge_and_mean(k)
87+
wf.connect([
88+
(xfibres, mms[k], [(k, 'inputnode.in_files')]),
89+
(mms[k], outputnode, [('outputnode.merged', k),
90+
('outputnode.mean', 'mean_%s' % k)])
91+
92+
])
93+
94+
# m_mdsamples = pe.Node(fsl.Merge(dimension="z"),
95+
# name="merge_mean_dsamples")
96+
wf.connect([
97+
(mms['thsamples'], make_dyads, [('outputnode.merged', 'theta_vol')]),
98+
(mms['phsamples'], make_dyads, [('outputnode.merged', 'phi_vol')]),
99+
#(xfibres, m_mdsamples, [('mean_dsamples', 'in_files')]),
100+
(make_dyads, outputnode, [('dyads', 'dyads'),
101+
('dispersion', 'dyads_disp')])
102+
])
80103
return wf
104+
105+
106+
def merge_and_mean(name='mm'):
107+
inputnode = pe.Node(niu.IdentityInterface(fields=['in_files']),
108+
name='inputnode')
109+
outputnode = pe.Node(niu.IdentityInterface(fields=['merged', 'mean']),
110+
name='outputnode')
111+
merge = pe.MapNode(fsl.Merge(dimension='z'), name='Merge',
112+
iterfield=['in_files'])
113+
mean = pe.MapNode(fsl.ImageMaths(op_string='-Tmean'), name='Mean',
114+
iterfield=['in_file'])
115+
116+
wf = pe.Workflow(name=name)
117+
wf.connect([
118+
(inputnode, merge, [(('in_files', transpose), 'in_files')]),
119+
(merge, mean, [('merged_file', 'in_file')]),
120+
(merge, outputnode, [('merged_file', 'merged')]),
121+
(mean, outputnode, [('out_file', 'mean')])
122+
])
123+
return wf
124+
125+
126+
def gen_chunks(dwi, mask, nchunks=6):
127+
import nibabel as nb
128+
import numpy as np
129+
130+
mask = nb.load(mask).get_data()
131+
mask[mask > 0] = 1
132+
mask[mask < 1] = 0
133+
nzels = np.nonzero(mask)
134+
np.savetxt('nonzeroidx.txt', nzels)
135+
136+
dshape = mask.shape
137+
mask = mask.reshape(-1).astype(np.uint8)
138+
els = np.sum(mask)
139+
chunkels = round(els / nchunks)
140+
141+
data = mask.copy()
142+
143+
out_files = []
144+
out_masks = []
145+
146+
for i in xrange(chunkels):
147+
first = i * chunkels
148+
last = (i+1) * chunkels + 1
149+
150+
chunk = data[first:last, ...]
151+
152+
fname = 'chunk%05d.nii.gz' % i
153+
nb.Nifti1Image(chunk, None, None).to_filename(fname)
154+
out_files.append(fname)
155+
156+
mname = 'mask%05d.nii.gz' % i
157+
nb.Nifti1Image(mask[first:last],
158+
None, None).to_filename(mname)
159+
out_masks.append(mname)
160+
161+
return out_files, out_masks
162+

0 commit comments

Comments
 (0)