Skip to content

Commit 23a9658

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 d07d4b0 commit 23a9658

File tree

15 files changed

+315
-22
lines changed

15 files changed

+315
-22
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():
@@ -244,21 +245,27 @@ def init_single_subject_wf(subject_id):
244245
anat_preproc_wf.__postdesc__ = (anat_preproc_wf.__postdesc__ or "") + f"""
245246
Diffusion data preprocessing
246247
247-
: For each of the {len(subject_data["dwi"])} dwi scans found per subject
248-
(across all sessions), the following preprocessing was performed."""
248+
: For each of the {len(subject_data["dwi"])} DWI scans found per subject
249+
(across all sessions), the gradient table was vetted and converted into the *RASb*
250+
format (i.e., given in RAS+ scanner coordinates, normalized b-vectors and scaled b-values),
251+
and a *b=0* average for reference to the subsequent steps of preprocessing was calculated.
252+
"""
249253

250254
layout = config.execution.layout
255+
dwi_data = tuple([
256+
(dwi, layout.get_metadata(dwi), layout.get_bvec(dwi), layout.get_bval(dwi))
257+
for dwi in subject_data["dwi"]
258+
])
251259
inputnode = pe.Node(niu.IdentityInterface(fields=["dwi_data"]),
252260
name="inputnode")
253-
inputnode.iterables = [(
254-
"dwi_data", tuple([
255-
(dwi, layout.get_bvec(dwi), layout.get_bval(dwi),
256-
layout.get_metadata(dwi)["PhaseEncodingDirection"])
257-
for dwi in subject_data["dwi"]
258-
])
259-
)]
261+
inputnode.iterables = [("dwi_data", dwi_data)]
262+
263+
referencenode = pe.JoinNode(niu.IdentityInterface(
264+
fields=["dwi_file", "metadata", "dwi_reference", "dwi_mask", "gradients_rasb"]),
265+
name="referencenode", joinsource="inputnode", run_without_submitting=True)
266+
260267
split_info = pe.Node(niu.Function(
261-
function=_unpack, output_names=["dwi_file", "bvec", "bval", "pedir"]),
268+
function=_unpack, output_names=["dwi_file", "metadata", "bvec", "bval"]),
262269
name="split_info", run_without_submitting=True)
263270

264271
early_b0ref_wf = init_early_b0ref_wf()
@@ -267,8 +274,21 @@ def init_single_subject_wf(subject_id):
267274
(split_info, early_b0ref_wf, [("dwi_file", "inputnode.dwi_file"),
268275
("bvec", "inputnode.in_bvec"),
269276
("bval", "inputnode.in_bval")]),
277+
(split_info, referencenode, [("dwi_file", "dwi_file"),
278+
("metadata", "metadata")]),
279+
(early_b0ref_wf, referencenode, [
280+
("outputnode.dwi_reference", "dwi_reference"),
281+
("outputnode.dwi_mask", "dwi_mask"),
282+
("outputnode.gradients_rasb", "gradients_rasb"),
283+
])
270284
])
271285

286+
fmap_estimation_wf = init_fmap_estimation_wf(subject_data["dwi"])
287+
workflow.connect([
288+
(referencenode, fmap_estimation_wf, [
289+
("dwi_reference", "inputnode.dwi_reference"),
290+
("dwi_mask", "inputnode.dwi_mask")]),
291+
])
272292
return workflow
273293

274294

0 commit comments

Comments
 (0)