Skip to content

Commit

Permalink
fix: revise registration workflow
Browse files Browse the repository at this point in the history
Since the affine between the target EPI and the fieldmap reference is
now applied "on-the-fly", the coefficients SHOULD NOT be reoriented
into the target space.

This also revises the test on the correction workflow, which also ran
registration (stacking potential problems by exercising several units)
so now the alignment matrix has been calculated offline and we can run
the test with and without it.

This commit requires the derivatives of the HCP dataset be up-to-date.
  • Loading branch information
oesteban committed Aug 7, 2023
1 parent f223ae1 commit ab21381
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 71 deletions.
28 changes: 4 additions & 24 deletions sdcflows/workflows/apply/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
The target EPI is the distorted dataset (or a reference thereof).
"""
from warnings import warn
from nipype.pipeline import engine as pe
from nipype.interfaces import utility as niu
from niworkflows.engine.workflows import LiterateWorkflow as Workflow
Expand Down Expand Up @@ -95,8 +96,6 @@ def init_coeff2epi_wf(
"""
from packaging.version import parse as parseversion, Version
from niworkflows.interfaces.fixes import FixHeaderRegistration as Registration
from ...interfaces.bspline import TransformCoefficients
from ...utils.misc import front as _pop

workflow = Workflow(name=name)
workflow.__desc__ = """\
Expand Down Expand Up @@ -132,6 +131,7 @@ def init_coeff2epi_wf(

# fmt: off
workflow.connect([
(inputnode, outputnode, [("fmap_coeff", "fmap_coeff")]),
(inputnode, coregister, [
("target_ref", "moving_image"),
("fmap_ref", "fixed_image"),
Expand All @@ -145,27 +145,7 @@ def init_coeff2epi_wf(
])
# fmt: on

if not write_coeff:
return workflow

# Resample the coefficients into the EPI grid
map_coeff = pe.Node(TransformCoefficients(), name="map_coeff")
map_coeff.interface._always_run = debug

# fmt: off
workflow.connect([
(inputnode, map_coeff, [("fmap_coeff", "in_coeff"),
("fmap_ref", "fmap_ref")]),
(coregister, map_coeff, [(("forward_transforms", _pop), "transform")]),
(map_coeff, outputnode, [("out_coeff", "fmap_coeff")]),
])
# fmt: on

if debug:
# fmt: off
workflow.connect([
(inputnode, map_coeff, [("target_ref", "fmap_target")]),
])
# fmt: on
if write_coeff:
warn("SDCFlows does not tinker with the coefficients file anymore")

return workflow
67 changes: 20 additions & 47 deletions sdcflows/workflows/apply/tests/test_correction.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,18 @@
# https://www.nipreps.org/community/licensing/
#
"""Test unwarp."""
from pathlib import Path
import json
from nipype.pipeline import engine as pe
from nipype.interfaces import utility as niu

from ...fit.fieldmap import init_magnitude_wf
from ..correction import init_unwarp_wf
from ..registration import init_coeff2epi_wf
from sdcflows.workflows.apply.correction import init_unwarp_wf


def test_unwarp_wf(tmpdir, datadir, workdir, outdir):
"""Test the unwarping workflow."""
tmpdir.chdir()

derivs_path = datadir / "HCP101006" / "derivatives" / "sdcflows-2.x"

distorted = (
datadir
/ "HCP101006"
Expand All @@ -42,44 +41,14 @@ def test_unwarp_wf(tmpdir, datadir, workdir, outdir):
/ "sub-101006_task-rest_dir-LR_sbref.nii.gz"
)

magnitude = (
datadir / "HCP101006" / "sub-101006" / "fmap" / "sub-101006_magnitude1.nii.gz"
workflow = init_unwarp_wf(omp_nthreads=2, debug=True)
workflow.inputs.inputnode.distorted = str(distorted)
workflow.inputs.inputnode.metadata = json.loads(
(distorted.parent / distorted.name.replace(".nii.gz", ".json")).read_text()
)
fmap_ref_wf = init_magnitude_wf(2, name="fmap_ref_wf")
fmap_ref_wf.inputs.inputnode.magnitude = magnitude

epi_ref_wf = init_magnitude_wf(2, name="epi_ref_wf")
epi_ref_wf.inputs.inputnode.magnitude = distorted

reg_wf = init_coeff2epi_wf(2, debug=True, sloppy=True, write_coeff=True)
reg_wf.inputs.inputnode.fmap_coeff = [Path(__file__).parent / "fieldcoeff.nii.gz"]

unwarp_wf = init_unwarp_wf(omp_nthreads=2, debug=True)
unwarp_wf.inputs.inputnode.metadata = {
"EffectiveEchoSpacing": 0.00058,
"PhaseEncodingDirection": "i",
}

workflow = pe.Workflow(name="test_unwarp_wf")
# fmt: off
workflow.connect([
(epi_ref_wf, unwarp_wf, [
("outputnode.fmap_ref", "inputnode.distorted"),
]),
(epi_ref_wf, reg_wf, [
("outputnode.fmap_ref", "inputnode.target_ref"),
("outputnode.fmap_mask", "inputnode.target_mask"),
]),
(fmap_ref_wf, reg_wf, [
("outputnode.fmap_ref", "inputnode.fmap_ref"),
("outputnode.fmap_mask", "inputnode.fmap_mask"),
]),
(reg_wf, unwarp_wf, [
("outputnode.fmap_coeff", "inputnode.fmap_coeff"),
("outputnode.target2fmap_xfm", "inputnode.data2fmap_xfm")
]),
])
# fmt:on
workflow.inputs.inputnode.fmap_coeff = [
str(derivs_path / "sub-101006_coeff-1_desc-topup_fieldmap.nii.gz")
]

if outdir:
from niworkflows.interfaces.reportlets.registration import (
Expand All @@ -88,12 +57,15 @@ def test_unwarp_wf(tmpdir, datadir, workdir, outdir):
from ...outputs import DerivativesDataSink
from ....interfaces.reportlets import FieldmapReportlet

unwarp_wf = workflow # Change variable name
workflow = pe.Workflow(name="outputs_unwarp_wf")
squeeze = pe.Node(niu.Function(function=_squeeze), name="squeeze")

report = pe.Node(
SimpleBeforeAfter(
before_label="Distorted",
after_label="Corrected",
before=str(distorted)
),
name="report",
mem_gb=0.1,
Expand All @@ -111,7 +83,7 @@ def test_unwarp_wf(tmpdir, datadir, workdir, outdir):
run_without_submitting=True,
)

rep = pe.Node(FieldmapReportlet(apply_mask=True), "simple_report")
rep = pe.Node(FieldmapReportlet(), "simple_report")
rep.interface._always_run = True

ds_fmap_report = pe.Node(
Expand All @@ -128,14 +100,15 @@ def test_unwarp_wf(tmpdir, datadir, workdir, outdir):

# fmt: off
workflow.connect([
(epi_ref_wf, report, [("outputnode.fmap_ref", "before")]),
(unwarp_wf, squeeze, [("outputnode.corrected", "in_file")]),
(unwarp_wf, report, [("outputnode.corrected_mask", "wm_seg")]),
(squeeze, report, [("out", "after")]),
(report, ds_report, [("out_report", "in_file")]),
(epi_ref_wf, rep, [("outputnode.fmap_ref", "reference"),
("outputnode.fmap_mask", "mask")]),
(unwarp_wf, rep, [("outputnode.fieldmap", "fieldmap")]),
(squeeze, rep, [("out", "reference")]),
(unwarp_wf, rep, [
("outputnode.fieldmap", "fieldmap"),
("outputnode.corrected_mask", "mask"),
]),
(rep, ds_fmap_report, [("out_report", "in_file")]),
])
# fmt: on
Expand Down
22 changes: 22 additions & 0 deletions sdcflows/workflows/apply/tests/test_registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,25 @@ def _gen_coeff(img):
out_file = Path("coeff.nii.gz").absolute()
bspline_grid(img).to_filename(out_file)
return str(out_file)


# ## Just in case we want to test with epis:
# reg_wf = init_coeff2epi_wf(2, debug=True, sloppy=True, write_coeff=True)
# reg_wf.inputs.inputnode.fmap_coeff = [
# str(derivs_path / "sub-101006_coeff-1_desc-topup_fieldmap.nii.gz")
# ]
# reg_wf.inputs.inputnode.fmap_ref = str(derivs_path / "sub-101006_desc-pepolar_epiref.nii.gz")
# reg_wf.inputs.inputnode.fmap_mask = str(derivs_path / "sub-101006_desc-pepolar_mask.nii.gz")
# reg_wf.inputs.inputnode.target_ref = str(
# derivs_path / "sub-101006_task-rest_dir-LR_desc-preproc_sbref.nii.gz"
# )
# reg_wf.inputs.inputnode.target_mask = str(
# derivs_path / "sub-101006_task-rest_dir-LR_desc-sbref_mask.nii.gz"
# )
# fmt: off
# workflow.connect([
# (reg_wf, unwarp_wf, [
# ("outputnode.target2fmap_xfm", "inputnode.data2fmap_xfm")
# ]),
# ])
# fmt:on

0 comments on commit ab21381

Please sign in to comment.