Skip to content

Commit 13c10f9

Browse files
committed
ENH: Utility that returns the B0FieldSource of a given potential EPI target
This code adds a ``get_identifier()`` interface that allows the user find the a list of ``B0FieldIdentifier``(s) that are associated with a given file. ATM, it pulls the information from the ``IntendedFor`` metadata of fieldmaps, but in the future, it should first read the ``B0FieldSource``. Originated-by: nipreps/dmriprep#140. Resolves: #148.
1 parent ecc3d0d commit 13c10f9

File tree

2 files changed

+71
-11
lines changed

2 files changed

+71
-11
lines changed

sdcflows/fieldmaps.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Utilities for fieldmap estimation."""
22
from pathlib import Path
33
from enum import Enum, auto
4+
from collections import defaultdict
45
import re
56
import attr
67
from json import loads
@@ -11,6 +12,7 @@
1112

1213

1314
_estimators = EstimatorRegistry()
15+
_intents = defaultdict(set)
1416

1517

1618
class MetadataError(ValueError):
@@ -367,6 +369,12 @@ def __attrs_post_init__(self):
367369
if self.method == EstimatorType.UNKNOWN:
368370
raise ValueError("Insufficient sources to estimate a fieldmap.")
369371

372+
intents_meta = set(
373+
el
374+
for f in self.sources
375+
for el in listify(f.metadata.get("IntendedFor") or [])
376+
)
377+
370378
# Register this estimation method
371379
if not self.bids_id:
372380
# If not manually set, try to get it from BIDS metadata
@@ -384,10 +392,15 @@ def __attrs_post_init__(self):
384392
elif bids_ids:
385393
object.__setattr__(self, "bids_id", bids_ids.pop())
386394
else:
387-
object.__setattr__(self, "bids_id", _estimators.add(self.paths()))
395+
bids_id = _estimators.add(self.paths())
396+
object.__setattr__(self, "bids_id", bids_id)
397+
for intent_file in intents_meta:
398+
_intents[intent_file].add(bids_id)
388399
return
389400

390401
_estimators[self.bids_id] = self.paths()
402+
for intent_file in intents_meta:
403+
_intents[intent_file].add(self.bids_id)
391404

392405
def paths(self):
393406
"""Return a tuple of paths that are sorted."""
@@ -424,3 +437,30 @@ def get_workflow(self, **kwargs):
424437
self._wf = init_syn_sdc_wf(**kwargs)
425438

426439
return self._wf
440+
441+
442+
def get_identifier(filename, by="IntendedFor"):
443+
"""
444+
Return the fieldmap identifier for a given filename.
445+
446+
Parameters
447+
----------
448+
filename : :obj:`str`
449+
The file we want to search in indexes.
450+
by : :obj:`str` (``IntendedFor`` or ``sources``)
451+
Index table in which the search should be performed.
452+
453+
"""
454+
if by == "IntendedFor":
455+
return tuple(sorted(_intents.get(filename, ())))
456+
457+
if by == "sources":
458+
return _estimators.get_key(filename)
459+
460+
raise KeyError(r"'{by}'")
461+
462+
463+
def clear_registry():
464+
"""Empty registries."""
465+
_estimators.clear()
466+
_intents.clear()

sdcflows/tests/test_fieldmaps.py

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def test_FieldmapEstimation(testdata_dir, inputfiles, method, nsources, raises):
6969
fm.FieldmapEstimation(sources)
7070

7171
# Clean up so this parameter set can be tested.
72-
fm._estimators.clear()
72+
fm.clear_registry()
7373

7474
fe = fm.FieldmapEstimation(sources)
7575
assert fe.method == method
@@ -109,17 +109,17 @@ def test_FieldmapEstimationError(testdata_dir, inputfiles, errortype):
109109
"""Test errors."""
110110
sub_dir = testdata_dir / "sub-01"
111111

112-
fm._estimators.clear()
112+
fm.clear_registry()
113113

114114
with pytest.raises(errortype):
115115
fm.FieldmapEstimation([sub_dir / f for f in inputfiles])
116116

117-
fm._estimators.clear()
117+
fm.clear_registry()
118118

119119

120-
def test_FieldmapEstimationIdentifier(testdata_dir):
120+
def test_FieldmapEstimationIdentifier(monkeypatch, testdata_dir):
121121
"""Check some use cases of B0FieldIdentifier."""
122-
fm._estimators.clear()
122+
fm.clear_registry()
123123

124124
with pytest.raises(ValueError):
125125
fm.FieldmapEstimation(
@@ -139,7 +139,11 @@ def test_FieldmapEstimationIdentifier(testdata_dir):
139139
[
140140
fm.FieldmapFile(
141141
testdata_dir / "sub-01" / "fmap/sub-01_fieldmap.nii.gz",
142-
metadata={"Units": "Hz", "B0FieldIdentifier": "fmap_0"},
142+
metadata={
143+
"Units": "Hz",
144+
"B0FieldIdentifier": "fmap_0",
145+
"IntendedFor": "file1.nii.gz",
146+
},
143147
),
144148
fm.FieldmapFile(
145149
testdata_dir / "sub-01" / "fmap/sub-01_magnitude.nii.gz",
@@ -148,6 +152,8 @@ def test_FieldmapEstimationIdentifier(testdata_dir):
148152
]
149153
)
150154
assert fe.bids_id == "fmap_0"
155+
assert fm.get_identifier("file1.nii.gz") == ("fmap_0",)
156+
assert not fm.get_identifier("file2.nii.gz")
151157

152158
with pytest.raises(KeyError):
153159
fm.FieldmapEstimation(
@@ -163,13 +169,17 @@ def test_FieldmapEstimationIdentifier(testdata_dir):
163169
]
164170
) # Consistent, but already exists
165171

166-
fm._estimators.clear()
172+
fm.clear_registry()
167173

168174
fe = fm.FieldmapEstimation(
169175
[
170176
fm.FieldmapFile(
171177
testdata_dir / "sub-01" / "fmap/sub-01_fieldmap.nii.gz",
172-
metadata={"Units": "Hz", "B0FieldIdentifier": "fmap_1"},
178+
metadata={
179+
"Units": "Hz",
180+
"B0FieldIdentifier": "fmap_1",
181+
"IntendedFor": ["file1.nii.gz", "file2.nii.gz"],
182+
},
173183
),
174184
fm.FieldmapFile(
175185
testdata_dir / "sub-01" / "fmap/sub-01_magnitude.nii.gz",
@@ -178,5 +188,15 @@ def test_FieldmapEstimationIdentifier(testdata_dir):
178188
]
179189
)
180190
assert fe.bids_id == "fmap_1"
181-
182-
fm._estimators.clear()
191+
assert fm.get_identifier("file1.nii.gz") == ("fmap_1",)
192+
assert fm.get_identifier("file2.nii.gz") == ("fmap_1",)
193+
assert not fm.get_identifier("file3.nii.gz")
194+
assert fm.get_identifier(
195+
str(testdata_dir / "sub-01" / "fmap/sub-01_magnitude.nii.gz"), by="sources"
196+
) == ("fmap_1",)
197+
198+
with monkeypatch.context() as m:
199+
m.setattr(fm, "_intents", {"file1.nii.gz": {"fmap_0", "fmap_1"}})
200+
assert fm.get_identifier("file1.nii.gz") == ("fmap_0", "fmap_1",)
201+
202+
fm.clear_registry()

0 commit comments

Comments
 (0)