Skip to content

Commit 31b7def

Browse files
committed
feat(TOPUP): an initial implementation of SD estimation.
Adds a new subworkflow based on FSL TOPUP to integrate SD estimation for the ds001771 dataset. - [x] Pin niworkflows to current master (while I release 1.2.0rc5 containing nipreps/niworkflows#503, nipreps/niworkflows#504, which are used here). - [x] Create a new sdc estimation workflow, with the expectation of upstreaming it to SDCFlows. - [x] Implement the barebones of how nipreps/sdcflows#101 could look like. Also to be upstreamed to SDCFlows when mature. - [x] Stick TOPUP from FSL 6.0.3 in the Docker image, since topup from FSL 5.0.x is really unstable (for instance, it fails with a segmentation fault on the workflow of ds001771) Resolves: #92
1 parent 25a20ba commit 31b7def

File tree

15 files changed

+324
-31
lines changed

15 files changed

+324
-31
lines changed

.docker/fsl-6.0/bin/topup

36.4 MB
Binary file not shown.

.docker/fsl-6.0/lib/libgfortran.so.3

1.13 MB
Binary file not shown.

.docker/fsl-6.0/lib/libopenblas.so.0

35 MB
Binary file not shown.

Dockerfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ ENV FSLDIR="/usr/share/fsl/5.0" \
9292
AFNI_PLUGINPATH="/usr/lib/afni/plugins"
9393
ENV PATH="/usr/lib/fsl/5.0:/usr/lib/afni/bin:$PATH"
9494

95+
COPY .docker/fsl-6.0/bin/topup /usr/share/fsl/5.0/bin/topup
96+
COPY .docker/fsl-6.0/lib/* /usr/lib/fsl/5.0/
97+
9598
# Installing ANTs 2.2.0 (NeuroDocker build)
9699
ENV ANTSPATH=/usr/lib/ants
97100
RUN mkdir -p $ANTSPATH && \

dmriprep/config/reports-spec.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,19 @@ sections:
2626
caption: Surfaces (white and pial) reconstructed with FreeSurfer (<code>recon-all</code>)
2727
overlaid on the participant's T1w template.
2828
subtitle: Surface reconstruction
29+
- name: Fieldmaps
30+
ordering: session,acquisition,run
31+
reportlets:
32+
- bids: {datatype: dwi, desc: pepolar, suffix: dwi}
33+
caption: Inhomogeneities of the *B0* field introduce (oftentimes severe) spatial distortions
34+
along the phase-encoding direction of the image. Utilizing two or more images with different
35+
phase-encoding polarities (PEPolar) or directions, it is possible to estimate the inhomogeneity
36+
of the field. The plot below shows a reference EPI (echo-planar imaging) volume generated
37+
using two or more EPI images with varying phase-encoding blips.
38+
description: Hover on the panels with the mouse pointer to also visualize the intensity of the
39+
inhomogeneity of the field in Hertz.
40+
static: false
41+
subtitle: "Susceptibility-derived Distortion Correction (SDC): field inhomogeneity estimation"
2942
- name: Diffusion
3043
ordering: session,acquisition,run
3144
reportlets:

dmriprep/data/flirtsch/b02b0.cnf

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Resolution (knot-spacing) of warps in mm
2+
--warpres=20,16,14,12,10,6,4,4,4
3+
# Subsampling level (a value of 2 indicates that a 2x2x2 neighbourhood is collapsed to 1 voxel)
4+
--subsamp=2,2,2,2,2,1,1,1,1
5+
# FWHM of gaussian smoothing
6+
--fwhm=8,6,4,3,3,2,1,0,0
7+
# Maximum number of iterations
8+
--miter=5,5,5,5,5,10,10,20,20
9+
# Relative weight of regularisation
10+
--lambda=0.005,0.001,0.0001,0.000015,0.000005,0.0000005,0.00000005,0.0000000005,0.00000000001
11+
# If set to 1 lambda is multiplied by the current average squared difference
12+
--ssqlambda=1
13+
# Regularisation model
14+
--regmod=bending_energy
15+
# If set to 1 movements are estimated along with the field
16+
--estmov=1,1,1,1,1,0,0,0,0
17+
# 0=Levenberg-Marquardt, 1=Scaled Conjugate Gradient
18+
--minmet=0,0,0,0,0,1,1,1,1
19+
# Quadratic or cubic splines
20+
--splineorder=3
21+
# Precision for calculation and storage of Hessian
22+
--numprec=double
23+
# Linear or spline interpolation
24+
--interp=spline
25+
# If set to 1 the images are individually scaled to a common mean intensity
26+
--scale=1

dmriprep/data/flirtsch/b02b0_1.cnf

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Resolution (knot-spacing) of warps in mm
2+
--warpres=20,16,14,12,10,6,4,4,4
3+
# Subsampling level (a value of 2 indicates that a 2x2x2 neighbourhood is collapsed to 1 voxel)
4+
--subsamp=1,1,1,1,1,1,1,1,1
5+
# FWHM of gaussian smoothing
6+
--fwhm=8,6,4,3,3,2,1,0,0
7+
# Maximum number of iterations
8+
--miter=5,5,5,5,5,10,10,20,20
9+
# Relative weight of regularisation
10+
--lambda=0.0005,0.0001,0.00001,0.0000015,0.0000005,0.0000005,0.00000005,0.0000000005,0.00000000001
11+
# If set to 1 lambda is multiplied by the current average squared difference
12+
--ssqlambda=1
13+
# Regularisation model
14+
--regmod=bending_energy
15+
# If set to 1 movements are estimated along with the field
16+
--estmov=1,1,1,1,1,0,0,0,0
17+
# 0=Levenberg-Marquardt, 1=Scaled Conjugate Gradient
18+
--minmet=0,0,0,0,0,1,1,1,1
19+
# Quadratic or cubic splines
20+
--splineorder=3
21+
# Precision for calculation and storage of Hessian
22+
--numprec=double
23+
# Linear or spline interpolation
24+
--interp=spline
25+
# If set to 1 the images are individually scaled to a common mean intensity
26+
--scale=1

dmriprep/data/flirtsch/b02b0_2.cnf

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Resolution (knot-spacing) of warps in mm
2+
--warpres=20,16,14,12,10,6,4,4,4
3+
# Subsampling level (a value of 2 indicates that a 2x2x2 neighbourhood is collapsed to 1 voxel)
4+
--subsamp=2,2,2,2,2,1,1,1,1
5+
# FWHM of gaussian smoothing
6+
--fwhm=8,6,4,3,3,2,1,0,0
7+
# Maximum number of iterations
8+
--miter=5,5,5,5,5,10,10,20,20
9+
# Relative weight of regularisation
10+
--lambda=0.005,0.001,0.0001,0.000015,0.000005,0.0000005,0.00000005,0.0000000005,0.00000000001
11+
# If set to 1 lambda is multiplied by the current average squared difference
12+
--ssqlambda=1
13+
# Regularisation model
14+
--regmod=bending_energy
15+
# If set to 1 movements are estimated along with the field
16+
--estmov=1,1,1,1,1,0,0,0,0
17+
# 0=Levenberg-Marquardt, 1=Scaled Conjugate Gradient
18+
--minmet=0,0,0,0,0,1,1,1,1
19+
# Quadratic or cubic splines
20+
--splineorder=3
21+
# Precision for calculation and storage of Hessian
22+
--numprec=double
23+
# Linear or spline interpolation
24+
--interp=spline
25+
# If set to 1 the images are individually scaled to a common mean intensity
26+
--scale=1

dmriprep/data/flirtsch/b02b0_4.cnf

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Resolution (knot-spacing) of warps in mm
2+
--warpres=20,16,14,12,10,6,4,4,4
3+
# Subsampling level (a value of 2 indicates that a 2x2x2 neighbourhood is collapsed to 1 voxel)
4+
--subsamp=4,4,2,2,2,1,1,1,1
5+
# FWHM of gaussian smoothing
6+
--fwhm=8,6,4,3,3,2,1,0,0
7+
# Maximum number of iterations
8+
--miter=5,5,5,5,5,10,10,20,20
9+
# Relative weight of regularisation
10+
--lambda=0.035,0.006,0.0001,0.000015,0.000005,0.0000005,0.00000005,0.0000000005,0.00000000001
11+
# If set to 1 lambda is multiplied by the current average squared difference
12+
--ssqlambda=1
13+
# Regularisation model
14+
--regmod=bending_energy
15+
# If set to 1 movements are estimated along with the field
16+
--estmov=1,1,1,1,1,0,0,0,0
17+
# 0=Levenberg-Marquardt, 1=Scaled Conjugate Gradient
18+
--minmet=0,0,0,0,0,1,1,1,1
19+
# Quadratic or cubic splines
20+
--splineorder=3
21+
# Precision for calculation and storage of Hessian
22+
--numprec=double
23+
# Linear or spline interpolation
24+
--interp=spline
25+
# If set to 1 the images are individually scaled to a common mean intensity
26+
--scale=1

dmriprep/workflows/base.py

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@
1212
BIDSInfo, BIDSFreeSurferDir
1313
)
1414
from niworkflows.utils.misc import fix_multi_T1w_source_name
15+
from niworkflows.utils.spaces import Reference
1516
from smriprep.workflows.anatomical import init_anat_preproc_wf
1617

17-
from niworkflows.utils.spaces import Reference
1818
from ..interfaces import DerivativesDataSink, BIDSDataGrabber
1919
from ..interfaces.reports import SubjectSummary, AboutSummary
2020
from ..utils.bids import collect_data
2121
from .dwi.base import init_early_b0ref_wf
22+
from .fmap.base import init_fmap_estimation_wf
2223

2324

2425
def init_dmriprep_wf():
@@ -253,21 +254,27 @@ def init_single_subject_wf(subject_id):
253254
anat_preproc_wf.__postdesc__ = (anat_preproc_wf.__postdesc__ or "") + f"""
254255
Diffusion data preprocessing
255256
256-
: For each of the {len(subject_data["dwi"])} dwi scans found per subject
257-
(across all sessions), the following preprocessing was performed."""
257+
: For each of the {len(subject_data["dwi"])} DWI scans found per subject
258+
(across all sessions), the gradient table was vetted and converted into the *RASb*
259+
format (i.e., given in RAS+ scanner coordinates, normalized b-vectors and scaled b-values),
260+
and a *b=0* average for reference to the subsequent steps of preprocessing was calculated.
261+
"""
258262

259263
layout = config.execution.layout
264+
dwi_data = tuple([
265+
(dwi, layout.get_metadata(dwi), layout.get_bvec(dwi), layout.get_bval(dwi))
266+
for dwi in subject_data["dwi"]
267+
])
260268
inputnode = pe.Node(niu.IdentityInterface(fields=["dwi_data"]),
261269
name="inputnode")
262-
inputnode.iterables = [(
263-
"dwi_data", tuple([
264-
(dwi, layout.get_bvec(dwi), layout.get_bval(dwi),
265-
layout.get_metadata(dwi)["PhaseEncodingDirection"])
266-
for dwi in subject_data["dwi"]
267-
])
268-
)]
270+
inputnode.iterables = [("dwi_data", dwi_data)]
271+
272+
referencenode = pe.JoinNode(niu.IdentityInterface(
273+
fields=["dwi_file", "metadata", "dwi_reference", "dwi_mask", "gradients_rasb"]),
274+
name="referencenode", joinsource="inputnode", run_without_submitting=True)
275+
269276
split_info = pe.Node(niu.Function(
270-
function=_unpack, output_names=["dwi_file", "bvec", "bval", "pedir"]),
277+
function=_unpack, output_names=["dwi_file", "metadata", "bvec", "bval"]),
271278
name="split_info", run_without_submitting=True)
272279

273280
early_b0ref_wf = init_early_b0ref_wf()
@@ -276,8 +283,21 @@ def init_single_subject_wf(subject_id):
276283
(split_info, early_b0ref_wf, [("dwi_file", "inputnode.dwi_file"),
277284
("bvec", "inputnode.in_bvec"),
278285
("bval", "inputnode.in_bval")]),
286+
(split_info, referencenode, [("dwi_file", "dwi_file"),
287+
("metadata", "metadata")]),
288+
(early_b0ref_wf, referencenode, [
289+
("outputnode.dwi_reference", "dwi_reference"),
290+
("outputnode.dwi_mask", "dwi_mask"),
291+
("outputnode.gradients_rasb", "gradients_rasb"),
292+
])
279293
])
280294

295+
fmap_estimation_wf = init_fmap_estimation_wf(subject_data["dwi"])
296+
workflow.connect([
297+
(referencenode, fmap_estimation_wf, [
298+
("dwi_reference", "inputnode.dwi_reference"),
299+
("dwi_mask", "inputnode.dwi_mask")]),
300+
])
281301
return workflow
282302

283303

0 commit comments

Comments
 (0)