Skip to content

Commit 59ec828

Browse files
committed
update dwi workflows
1 parent 20a2201 commit 59ec828

File tree

9 files changed

+247
-422
lines changed

9 files changed

+247
-422
lines changed

dmriprep/workflows/dwi/__init__.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,23 @@
66
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
77
88
.. automodule:: dmriprep.workflows.dwi.base
9-
.. automodule:: dmriprep.workflows.dwi.prep_dwi
9+
.. automodule:: dmriprep.workflows.dwi.artifacts
10+
.. automodule:: dmriprep.workflows.dwi.eddy
1011
.. automodule:: dmriprep.workflows.dwi.tensor
1112
.. automodule:: dmriprep.workflows.dwi.outputs
1213
1314
"""
1415

1516
from .base import init_dwi_preproc_wf
16-
from .prep_dwi import init_prep_dwi_wf
17-
from .tensor import init_tensor_wf
18-
from .outputs import init_output_wf
17+
from .artifacts import init_dwi_artifacts_wf
18+
from .eddy import init_dwi_eddy_wf
19+
from .tensor import init_dwi_tensor_wf
20+
from .outputs import init_dwi_derivatives_wf
1921

2022
__all__ = [
2123
"init_dwi_preproc_wf",
22-
"init_prep_dwi_wf",
23-
"init_tensor_wf",
24-
"init_output_wf"
24+
"init_dwi_artifacts_wf",
25+
"init_dwi_eddy_wf",
26+
"init_dwi_tensor_wf",
27+
"init_dwi_derivatives_wf"
2528
]

dmriprep/workflows/dwi/artifacts.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# -*- coding: utf-8 -*-
2+
3+
"""
4+
Artefact removal
5+
^^^^^^^^^^^^^^^^
6+
7+
.. autofunction:: init_dwi_artifacts_wf
8+
9+
"""
10+
11+
from nipype.pipeline import engine as pe
12+
from nipype.interfaces import mrtrix3, utility as niu
13+
14+
15+
def init_dwi_artifacts_wf(ignore):
16+
"""
17+
This workflow performs denoising and unringing on the input dwi image.
18+
19+
Denoising is done using Mrtrix3's implementation of the MP-PCA
20+
algorithm `[Veraart2016a_]` and `[Veraart2016b_]`.
21+
Unringing is done using Mrtrix3 `[Kellner2016_]`.
22+
23+
.. workflow::
24+
:graph2use: orig
25+
:simple_form: yes
26+
27+
from dmriprep.workflows.dwi import init_dwi_artifacts_wf
28+
wf = init_dwi_artifacts_wf(ignore=[])
29+
30+
**Parameters**
31+
32+
ignore : list
33+
List of artefact removal steps to skip (default: [])
34+
35+
**Inputs**
36+
37+
dwi_file
38+
dwi NIfTI file
39+
40+
**Outputs**
41+
42+
out_file
43+
dwi NIfTI file after artefact removal
44+
45+
References
46+
^^^^^^^^^^
47+
48+
.. [Veraart2016a] Veraart, J.; Novikov, D.S.; Christiaens, D.; Ades-aron, B.;
49+
Sijbers, J. & Fieremans, E. Denoising of diffusion MRI
50+
using random matrix theory. NeuroImage, 2016, 142, 394-406,
51+
doi: `10.1016/j.neuroimage.2016.08.016 <https://doi.org/10.1016/j.neuroimage.2016.08.016>`_.
52+
53+
.. [Veraart2016b] Veraart, J.; Fieremans, E. & Novikov, D.S. Diffusion MRI
54+
noise mapping using random matrix theory. Magn. Res. Med.,
55+
2016, 76(5), 1582-1593,
56+
doi: `10.1002/mrm.26059 <https://doi.org/10.1002/mrm.26059>`_.
57+
58+
.. [Kellner2016] Kellner, E; Dhital, B; Kiselev, V.G & Reisert, M.
59+
Gibbs-ringing artifact removal based on local subvoxel-shifts.
60+
Magnetic Resonance in Medicine, 2016, 76, 1574–1581,
61+
doi: `10.1002/mrm.26054 <https://doi.org/10.1002/mrm.26054>`_.
62+
63+
"""
64+
65+
wf = pe.Workflow(name="dwi_artifacts_wf")
66+
67+
inputnode = pe.Node(niu.IdentityInterface(fields=["dwi_file"]), name="inputnode")
68+
69+
outputnode = pe.Node(niu.IdentityInterface(fields=["out_file"]), name="outputnode")
70+
71+
denoise = pe.Node(mrtrix3.DWIDenoise(), name="denoise")
72+
73+
unring = pe.Node(mrtrix3.MRDeGibbs(), name="unring")
74+
75+
if ignore == ["denoise"]:
76+
wf.connect([
77+
(inputnode, unring, [("dwi_file", "in_file")]),
78+
(unring, outputnode, [("out_file", "out_file")])
79+
])
80+
81+
elif ignore == ["unring"]:
82+
wf.connect([
83+
(inputnode, denoise, [("dwi_file", "in_file")]),
84+
(denoise, outputnode, [("out_file", "out_file")])
85+
])
86+
87+
elif ["denoise", "unring"] in ignore:
88+
wf.connect([
89+
(inputnode, outputnode, "dwi_file", "out_file")
90+
])
91+
92+
else:
93+
wf.connect([
94+
(inputnode, denoise, [("dwi_file", "in_file")]),
95+
(denoise, unring, [("out_file", "in_file")]),
96+
(unring, outputnode, [("out_file", "out_file")])
97+
])
98+
99+
return wf

dmriprep/workflows/dwi/base.py

Lines changed: 73 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -10,49 +10,61 @@
1010

1111
from bids import BIDSLayout
1212
from nipype.pipeline import engine as pe
13-
from nipype.interfaces import ants, fsl, mrtrix3, utility as niu
13+
from nipype.interfaces import fsl, mrtrix3, utility as niu
1414
from numba import cuda
1515

16-
from .prep_dwi import init_prep_dwi_wf
17-
from .tensor import init_tensor_wf
16+
from .artifacts import init_dwi_artifacts_wf
17+
from .tensor import init_dwi_tensor_wf
1818

19-
# from ..fieldmap.base import init_sdc_prep_wf
19+
from ..fieldmap.base import init_sdc_prep_wf
2020

2121
FMAP_PRIORITY = {"epi": 0, "fieldmap": 1, "phasediff": 2, "phase": 3, "syn": 4}
2222

2323

24-
def init_dwi_preproc_wf(subject_id, dwi_file, metadata, parameters):
24+
def init_dwi_preproc_wf(
25+
subject_id,
26+
dwi_file,
27+
metadata,
28+
layout,
29+
ignore,
30+
b0_thresh,
31+
output_resolution,
32+
bet_dwi,
33+
bet_mag,
34+
omp_nthreads,
35+
synb0_dir
36+
):
37+
38+
fmaps = []
39+
synb0 = ""
40+
41+
# If use_synb0 set, get synb0 from files
42+
if synb0_dir:
43+
synb0_layout = BIDSLayout(
44+
synb0_dir, validate=False, derivatives=True
45+
)
46+
synb0 = synb0_layout.get(subject=subject_id, return_type="file")[0]
47+
else:
48+
fmaps = layout.get_fieldmap(dwi_file, return_list=True)
49+
if not fmaps:
50+
raise Exception(
51+
"No fieldmaps found for participant {}. "
52+
"All workflows require fieldmaps".format(subject_id)
53+
)
2554

26-
# fmaps = []
27-
# synb0 = ""
28-
#
29-
# # If use_synb0 set, get synb0 from files
30-
# if parameters.synb0_dir:
31-
# synb0_layout = BIDSLayout(
32-
# parameters.synb0_dir, validate=False, derivatives=True
33-
# )
34-
# synb0 = synb0_layout.get(subject=subject_id, return_type="file")[0]
35-
# else:
36-
# fmaps = parameters.layout.get_fieldmap(dwi_file, return_list=True)
37-
# if not fmaps:
38-
# raise Exception(
39-
# "No fieldmaps found for participant {}. "
40-
# "All workflows require fieldmaps".format(subject_id)
41-
# )
42-
#
43-
# for fmap in fmaps:
44-
# fmap["metadata"] = parameters.layout.get_metadata(
45-
# fmap[fmap["suffix"]]
46-
# )
47-
#
48-
# sdc_wf = init_sdc_prep_wf(
49-
# subject_id,
50-
# fmaps,
51-
# metadata,
52-
# parameters.layout,
53-
# parameters.bet_mag,
54-
# synb0,
55-
# )
55+
for fmap in fmaps:
56+
fmap["metadata"] = layout.get_metadata(
57+
fmap[fmap["suffix"]]
58+
)
59+
60+
sdc_wf = init_sdc_prep_wf(
61+
subject_id,
62+
fmaps,
63+
metadata,
64+
layout,
65+
bet_mag,
66+
synb0,
67+
)
5668

5769
multiple_runs = isinstance(dwi_file, list)
5870

@@ -102,7 +114,7 @@ def init_dwi_preproc_wf(subject_id, dwi_file, metadata, parameters):
102114
name="outputnode",
103115
)
104116

105-
dwi_prep_wf = init_prep_dwi_wf(parameters.ignore, parameters.output_resolution)
117+
dwi_artifacts_wf = init_dwi_artifacts_wf(ignore)
106118

107119
def gen_index(in_file):
108120
"""
@@ -118,6 +130,7 @@ def gen_index(in_file):
118130
119131
out_file
120132
The output index file.
133+
121134
"""
122135

123136
import os
@@ -143,6 +156,23 @@ def gen_index(in_file):
143156
)
144157

145158
def gen_acqparams(in_file, metadata):
159+
"""
160+
Create an acquisition parameters file for ``eddy``
161+
162+
**Inputs**
163+
164+
in_file
165+
The dwi file
166+
metadata
167+
The BIDS metadata of the dwi file
168+
169+
**Outputs**
170+
171+
out_file
172+
The output acquisition parameters file
173+
174+
"""
175+
146176
import os
147177
from nipype.utils.filemanip import fname_presuffix
148178

@@ -189,7 +219,7 @@ def gen_acqparams(in_file, metadata):
189219

190220
def b0_average(in_dwi, in_bval, b0_thresh, out_file=None):
191221
"""
192-
A function that averages the *b0* volumes from a DWI dataset.
222+
Averages the *b0* volumes from a DWI dataset.
193223
As current dMRI data are being acquired with all b-values > 0.0,
194224
the *lowb* volumes are selected by specifying the parameter b0_thresh.
195225
.. warning:: *b0* should be already registered (head motion artifact
@@ -229,16 +259,16 @@ def b0_average(in_dwi, in_bval, b0_thresh, out_file=None):
229259
name="b0_avg_pre",
230260
)
231261

232-
avg_b0_0.inputs.b0_thresh = parameters.b0_thresh
262+
avg_b0_0.inputs.b0_thresh = b0_thresh
233263

234264
bet_dwi0 = pe.Node(
235-
fsl.BET(frac=parameters.bet_dwi, mask=True, robust=True), name="bet_dwi_pre"
265+
fsl.BET(frac=bet_dwi, mask=True, robust=True), name="bet_dwi_pre"
236266
)
237267

238268
ecc = pe.Node(fsl.Eddy(repol=True, cnr_maps=True, residuals=True), name="fsl_eddy")
239269

240-
if parameters.omp_nthreads:
241-
ecc.inputs.num_threads = parameters.omp_nthreads
270+
if omp_nthreads:
271+
ecc.inputs.num_threads = omp_nthreads
242272

243273
try:
244274
if cuda.gpus:
@@ -253,15 +283,6 @@ def b0_average(in_dwi, in_bval, b0_thresh, out_file=None):
253283
get_path = lambda x: x.split(".nii.gz")[0].split("_fix")[0]
254284
get_qc_path = lambda x: x.split(".nii.gz")[0] + ".qc"
255285

256-
if set(parameters.ignore) == set(["denoise", "unring"]):
257-
wf.connect(
258-
[
259-
(inputnode, avg_b0_0, [("dwi_file", "in_file")])(
260-
inputnode, ecc, [("dwi_file", "in_file")]
261-
)
262-
]
263-
)
264-
265286
fslroi = pe.Node(fsl.ExtractROI(t_min=0, t_size=1), name="fslroi")
266287

267288
bias_correct = pe.Node(mrtrix3.DWIBiasCorrect(use_ants=True), name="bias_correct")
@@ -342,7 +363,7 @@ def get_b0_mask_fn(b0_file):
342363
)
343364

344365
# # If synb0 is meant to be used
345-
# if parameters.synb0_dir:
366+
# if synb0_dir:
346367
# dwi_wf.connect(
347368
# [
348369
# (
@@ -360,7 +381,7 @@ def get_b0_mask_fn(b0_file):
360381
# ),
361382
# ]
362383
# )
363-
# ecc.inputs.in_acqp = parameters.acqp_file
384+
# ecc.inputs.in_acqp = acqp_file
364385
# else:
365386
# # Decide what ecc will take: topup or fmap
366387
# fmaps.sort(key=lambda fmap: FMAP_PRIORITY[fmap["suffix"]])

0 commit comments

Comments
 (0)