Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft MEDIC dynamic distortion correction method (second attempt) #438

Draft
wants to merge 20 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions env.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ dependencies:
# Workflow dependencies: FSL (versions pinned in 6.0.6.2)
- fsl-fugue=2201.2
- fsl-topup=2203.1
# Workflow dependencies: Julia
- julia=1.9.4
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ dependencies = [
"scipy >= 1.8.1",
"templateflow",
"toml",
"warpkit == 0.1.1",
]
dynamic = ["version"]

Expand Down
12 changes: 9 additions & 3 deletions sdcflows/fieldmaps.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
PHASEDIFF = auto()
MAPPED = auto()
ANAT = auto()
MEDIC = auto()


MODALITIES = {
Expand All @@ -67,6 +68,7 @@
"sbref": EstimatorType.PEPOLAR,
"T1w": EstimatorType.ANAT,
"T2w": EstimatorType.ANAT,
"medic": EstimatorType.MEDIC,
}


Expand Down Expand Up @@ -313,16 +315,20 @@

# Fieldmap option 1: actual field-mapping sequences
fmap_types = suffix_set.intersection(
("fieldmap", "phasediff", "phase1", "phase2")
("fieldmap", "phasediff", "phase1", "phase2", "bold")
)
if len(fmap_types) > 1 and fmap_types - set(("phase1", "phase2")):
raise TypeError(f"Incompatible suffices found: <{','.join(fmap_types)}>.")
raise TypeError(f"Incompatible suffixes found: <{','.join(fmap_types)}>.")

Check warning on line 321 in sdcflows/fieldmaps.py

View check run for this annotation

Codecov / codecov/patch

sdcflows/fieldmaps.py#L321

Added line #L321 was not covered by tests

# Check for MEDIC
if "part-mag" in self.sources[0].path:
fmap_types = set(list(fmap_types) + ["medic"])

Check warning on line 325 in sdcflows/fieldmaps.py

View check run for this annotation

Codecov / codecov/patch

sdcflows/fieldmaps.py#L325

Added line #L325 was not covered by tests

if fmap_types:
sources = sorted(
f.path
for f in self.sources
if f.suffix in ("fieldmap", "phasediff", "phase1", "phase2")
if f.suffix in ("fieldmap", "phasediff", "phase1", "phase2", "bold")
)

# Automagically add the corresponding phase2 file if missing as argument
Expand Down
114 changes: 114 additions & 0 deletions sdcflows/interfaces/fmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
from nipype import logging
from nipype.interfaces.base import (
BaseInterfaceInputSpec,
CommandLineInputSpec,
CommandLine,
TraitedSpec,
File,
traits,
Expand Down Expand Up @@ -62,6 +64,27 @@
return runtime


class _PhaseMap2rads2InputSpec(BaseInterfaceInputSpec):
in_file = File(exists=True, mandatory=True, desc="input (wrapped) phase map")


class _PhaseMap2rads2OutputSpec(TraitedSpec):
out_file = File(desc="the phase map in the range -3.14 - 3.14")


class PhaseMap2rads2(SimpleInterface):
"""Convert a phase map given in a.u. (e.g., 0-4096) to radians."""

input_spec = _PhaseMap2rads2InputSpec
output_spec = _PhaseMap2rads2OutputSpec

def _run_interface(self, runtime):
from ..utils.phasemanip import au2rads2

Check warning on line 82 in sdcflows/interfaces/fmap.py

View check run for this annotation

Codecov / codecov/patch

sdcflows/interfaces/fmap.py#L82

Added line #L82 was not covered by tests

self._results["out_file"] = au2rads2(self.inputs.in_file, newpath=runtime.cwd)
return runtime

Check warning on line 85 in sdcflows/interfaces/fmap.py

View check run for this annotation

Codecov / codecov/patch

sdcflows/interfaces/fmap.py#L84-L85

Added lines #L84 - L85 were not covered by tests


class _SubtractPhasesInputSpec(BaseInterfaceInputSpec):
in_phases = traits.List(File(exists=True), min=1, max=2, desc="input phase maps")
in_meta = traits.List(
Expand Down Expand Up @@ -390,3 +413,94 @@
f"{img1.get_filename()} {''.join(nb.aff2axcodes(img1.affine))}, "
f"{img2.get_filename()} {''.join(nb.aff2axcodes(img2.affine))}"
)


class _MEDICInputSpec(CommandLineInputSpec):
mag_files = traits.List(
File(exists=True),
argstr="--magnitude %s",
mandatory=True,
minlen=2,
desc="Magnitude image(s) to verify registration",
)
phase_files = traits.List(
File(exists=True),
argstr="--phase %s",
mandatory=True,
minlen=2,
desc="Phase image(s) to verify registration",
)
metadata = traits.List(
File(exists=True),
argstr="--metadata %s",
mandatory=True,
minlen=2,
desc="Metadata corresponding to the inputs",
)
prefix = traits.Str(
"medic",
argstr="--out_prefix %s",
usedefault=True,
desc="Prefix for output files",
)
noise_frames = traits.Int(
0,
argstr="--noiseframes %d",
usedefault=True,
desc="Number of noise frames to remove",
)
n_cpus = traits.Int(
4,
argstr="--n_cpus %d",
usedefault=True,
desc="Number of CPUs to use",
)
debug = traits.Bool(
False,
argstr="--debug",
usedefault=True,
desc="Enable debugging output",
)
wrap_limit = traits.Bool(
False,
argstr="--wrap_limit",
usedefault=True,
desc="Turns off some heuristics for phase unwrapping",
)


class _MEDICOutputSpec(TraitedSpec):
native_field_map = File(
exists=True,
desc="4D ative (distorted) space field map in Hertz",
)
displacement_map = File(
exists=True,
desc="4D displacement map in millimeters",
)
field_map = File(
exists=True,
desc="4D undistorted field map in Hertz",
)


class MEDIC(CommandLine):
"""Run MEDIC."""

_cmd = "medic"
input_spec = _MEDICInputSpec
output_spec = _MEDICOutputSpec

def _list_outputs(self):
outputs = self._outputs().get()
out_dir = os.getcwd()
outputs['native_field_map'] = os.path.join(

Check warning on line 497 in sdcflows/interfaces/fmap.py

View check run for this annotation

Codecov / codecov/patch

sdcflows/interfaces/fmap.py#L495-L497

Added lines #L495 - L497 were not covered by tests
out_dir,
f'{self.inputs.prefix}_fieldmaps_native.nii',
)
outputs['displacement_map'] = os.path.join(

Check warning on line 501 in sdcflows/interfaces/fmap.py

View check run for this annotation

Codecov / codecov/patch

sdcflows/interfaces/fmap.py#L501

Added line #L501 was not covered by tests
out_dir,
f'{self.inputs.prefix}_displacementmaps.nii',
)
outputs['field_map'] = os.path.join(out_dir, f'{self.inputs.prefix}_fieldmaps.nii')
return outputs

Check warning on line 506 in sdcflows/interfaces/fmap.py

View check run for this annotation

Codecov / codecov/patch

sdcflows/interfaces/fmap.py#L505-L506

Added lines #L505 - L506 were not covered by tests
11 changes: 11 additions & 0 deletions sdcflows/tests/data/dsD/dataset_description.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"Name": "Test Dataset D for MEDIC, only empty files",
"BIDSVersion": "",
"License": "CC0",
"Authors": ["Salo T."],
"Acknowledgements": "",
"HowToAcknowledge": "",
"Funding": "",
"ReferencesAndLinks": [""],
"DatasetDOI": ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
{
"B0FieldIdentifier": "medic",
"B0FieldSource": "medic",
"EchoTime": 0.0142,
"FlipAngle": 68,
"ImageType": [
"ORIGINAL",
"PRIMARY",
"M",
"MB",
"TE2",
"ND",
"NORM",
"MOSAIC"
],
"PhaseEncodingDirection": "j",
"RepetitionTime": 1.761,
"SliceTiming": [
0,
0.725,
1.45,
0.435,
1.16,
0.145,
0.87,
1.595,
0.58,
1.305,
0.29,
1.015,
0,
0.725,
1.45,
0.435,
1.16,
0.145,
0.87,
1.595,
0.58,
1.305,
0.29,
1.015,
0,
0.725,
1.45,
0.435,
1.16,
0.145,
0.87,
1.595,
0.58,
1.305,
0.29,
1.015,
0,
0.725,
1.45,
0.435,
1.16,
0.145,
0.87,
1.595,
0.58,
1.305,
0.29,
1.015,
0,
0.725,
1.45,
0.435,
1.16,
0.145,
0.87,
1.595,
0.58,
1.305,
0.29,
1.015,
0,
0.725,
1.45,
0.435,
1.16,
0.145,
0.87,
1.595,
0.58,
1.305,
0.29,
1.015
],
"SpacingBetweenSlices": 2,
"TotalReadoutTime": 0.03
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
{
"B0FieldIdentifier": "medic",
"B0FieldSource": "medic",
"EchoTime": 0.0142,
"FlipAngle": 68,
"ImageType": [
"ORIGINAL",
"PRIMARY",
"P",
"MB",
"TE1",
"ND",
"MOSAIC",
"PHASE"
],
"PhaseEncodingDirection": "j",
"RepetitionTime": 1.761,
"SliceTiming": [
0,
0.725,
1.45,
0.435,
1.16,
0.145,
0.87,
1.595,
0.58,
1.305,
0.29,
1.015,
0,
0.725,
1.45,
0.435,
1.16,
0.145,
0.87,
1.595,
0.58,
1.305,
0.29,
1.015,
0,
0.725,
1.45,
0.435,
1.16,
0.145,
0.87,
1.595,
0.58,
1.305,
0.29,
1.015,
0,
0.725,
1.45,
0.435,
1.16,
0.145,
0.87,
1.595,
0.58,
1.305,
0.29,
1.015,
0,
0.725,
1.45,
0.435,
1.16,
0.145,
0.87,
1.595,
0.58,
1.305,
0.29,
1.015,
0,
0.725,
1.45,
0.435,
1.16,
0.145,
0.87,
1.595,
0.58,
1.305,
0.29,
1.015
],
"SpacingBetweenSlices": 2,
"TotalReadoutTime": 0.03,
"Units": "arbitrary"
}
Loading
Loading