sdcflows.utils.wrangler module

Find fieldmaps on the BIDS inputs for SDC.

sdcflows.utils.wrangler.find_estimators(*, layout: bids.layout.layout.BIDSLayout, subject: str, sessions: Optional[List[str]] = None, fmapless: Union[bool, set] = True, force_fmapless: bool = False, logger: Optional[logging.Logger] = None, bids_filters: Optional[dict] = None) list[source]

Apply basic heuristics to automatically find available data for fieldmap estimation.

The “fieldmap-less” heuristics only attempt to find _dwi and _bold candidates to pair with a _T1w anatomical reference. For more complicated heuristics (for instance, using _T2w images or _sbref images,) the FieldmapEstimation object must be created manually by the user.

Parameters
  • layout (bids.layout.BIDSLayout) – An initialized PyBIDS layout.

  • subject (str) – Participant label for this single-subject workflow.

  • sessions (list or None) – One of more session identifiers. If None, all sessions will be used.

  • fmapless (bool or set) – Indicates if fieldmap-less heuristics should be executed. When fmapless is a set, it can contain valid BIDS suffices for EPI images (namely, "dwi", "bold", or "sbref"). When fmapless is True, heuristics will use the {"bold", "dwi"} set.

  • force_fmapless (bool) – When some other fieldmap estimation methods have been found, fieldmap-less estimation will be skipped except if force_fmapless is True.

  • logger – The logger used to relay messages. If not provided, one will be created.

  • bids_filters – Optional dictionary of key/values to filter the entities on. This allows lower level file inclusion/exclusion.

Returns

estimators – The list of FieldmapEstimation objects that have successfully been built (meaning, all necessary inputs and corresponding metadata are present in the given layout.)

Return type

list

Examples

Our ds000054 dataset, created for fMRIPrep, only has one phasediff type of fieldmap with magnitude1 and magnitude2 files:

>>> find_estimators(
...     layout=layouts['ds000054'],
...     subject="100185",
...     fmapless=False,
... )  
[FieldmapEstimation(sources=<3 files>, method=<EstimatorType.PHASEDIFF: 3>,
                    bids_id='auto_00000')]

OpenNeuro’s dataset with four PEPOLAR EPI files, two runs per phase-encoding direction (AP, PA):

>>> find_estimators(
...     layout=layouts['ds001771'],
...     subject="36",
... )  
[FieldmapEstimation(sources=<4 files>, method=<EstimatorType.PEPOLAR: 2>,
                    bids_id='auto_00001')]

OpenNeuro’s ds001600 is an SDC test-dataset containing many different possibilities for fieldmap estimation:

>>> find_estimators(
...     layout=layouts['ds001600'],
...     subject="1",
... )  
[FieldmapEstimation(sources=<4 files>, method=<EstimatorType.PHASEDIFF: 3>,
                    bids_id='auto_00002'),
 FieldmapEstimation(sources=<4 files>, method=<EstimatorType.PHASEDIFF: 3>,
                    bids_id='auto_00003'),
 FieldmapEstimation(sources=<3 files>, method=<EstimatorType.PHASEDIFF: 3>,
                    bids_id='auto_00004'),
 FieldmapEstimation(sources=<2 files>, method=<EstimatorType.PEPOLAR: 2>,
                    bids_id='auto_00005')]

We can also pick one (simplified) HCP subject for testing purposes:

>>> find_estimators(
...     layout=layouts['HCP101006'],
...     subject="101006",
... )  
[FieldmapEstimation(sources=<2 files>, method=<EstimatorType.PHASEDIFF: 3>,
                    bids_id='auto_00006'),
 FieldmapEstimation(sources=<2 files>, method=<EstimatorType.PEPOLAR: 2>,
                    bids_id='auto_00007')]

Finally, SDCFlows’ “dataset A” and “dataset B” contain BIDS structures with zero-byte NIfTI files and some corresponding metadata:

>>> find_estimators(
...     layout=layouts['dsA'],
...     subject="01",
... )  
[FieldmapEstimation(sources=<2 files>, method=<EstimatorType.MAPPED: 4>,
                    bids_id='auto_...'),
 FieldmapEstimation(sources=<4 files>, method=<EstimatorType.PHASEDIFF: 3>,
                    bids_id='auto_...'),
 FieldmapEstimation(sources=<3 files>, method=<EstimatorType.PHASEDIFF: 3>,
                    bids_id='auto_...'),
 FieldmapEstimation(sources=<4 files>, method=<EstimatorType.PEPOLAR: 2>,
                    bids_id='auto_...'),
 FieldmapEstimation(sources=<2 files>, method=<EstimatorType.PEPOLAR: 2>,
                    bids_id='auto_...')]
>>> find_estimators(
...     layout=layouts['dsB'],
...     subject="01",
... )  
[FieldmapEstimation(sources=<2 files>, method=<EstimatorType.MAPPED: 4>,
                    bids_id='auto_...'),
 FieldmapEstimation(sources=<4 files>, method=<EstimatorType.PHASEDIFF: 3>,
                    bids_id='auto_...'),
 FieldmapEstimation(sources=<3 files>, method=<EstimatorType.PHASEDIFF: 3>,
                    bids_id='auto_...'),
 FieldmapEstimation(sources=<4 files>, method=<EstimatorType.PEPOLAR: 2>,
                    bids_id='auto_...'),
 FieldmapEstimation(sources=<2 files>, method=<EstimatorType.PEPOLAR: 2>,
                    bids_id='auto_...')]

After cleaning the registry, we can see how the “fieldmap-less” estimation can be forced:

>>> from .. import fieldmaps as fm
>>> fm.clear_registry()
>>> find_estimators(
...     layout=layouts['ds000054'],
...     subject="100185",
...     fmapless={"bold"},
...     force_fmapless=True,
... )  
[FieldmapEstimation(sources=<3 files>, method=<EstimatorType.PHASEDIFF: 3>,
                    bids_id='auto_00000'),
 FieldmapEstimation(sources=<3 files>, method=<EstimatorType.ANAT: 5>,
                    bids_id='auto_00001')]

Likewise in a more comprehensive dataset:

>>> find_estimators(
...     layout=layouts['ds001771'],
...     subject="36",
...     force_fmapless=True,
... )  
[FieldmapEstimation(sources=<4 files>, method=<EstimatorType.PEPOLAR: 2>,
                   bids_id='auto_00002'),
FieldmapEstimation(sources=<7 files>, method=<EstimatorType.ANAT: 5>,
                   bids_id='auto_00003'),
FieldmapEstimation(sources=<2 files>, method=<EstimatorType.ANAT: 5>,
                   bids_id='auto_00004'),
FieldmapEstimation(sources=<2 files>, method=<EstimatorType.ANAT: 5>,
                   bids_id='auto_00005')]

Because “dataset A” contains very few metadata fields available, “fieldmap-less” heuristics come back empty (BOLD and DWI files are missing the mandatory PhaseEncodingDirection, in this case):

>>> find_estimators(
...     layout=layouts['dsA'],
...     subject="01",
...     force_fmapless=True,
... )  
[FieldmapEstimation(sources=<2 files>, method=<EstimatorType.MAPPED: 4>,
                    bids_id='auto_...'),
 FieldmapEstimation(sources=<4 files>, method=<EstimatorType.PHASEDIFF: 3>,
                    bids_id='auto_...'),
 FieldmapEstimation(sources=<3 files>, method=<EstimatorType.PHASEDIFF: 3>,
                    bids_id='auto_...'),
 FieldmapEstimation(sources=<4 files>, method=<EstimatorType.PEPOLAR: 2>,
                    bids_id='auto_...'),
 FieldmapEstimation(sources=<2 files>, method=<EstimatorType.PEPOLAR: 2>,
                    bids_id='auto_...')]

This function should also correctly investigate multi-session datasets:

>>> find_estimators(
...     layout=layouts['ds000206'],
...     subject="05",
...     fmapless=False,
...     force_fmapless=False,
... )  
[]
>>> find_estimators(
...     layout=layouts['ds000206'],
...     subject="05",
...     fmapless=True,
...     force_fmapless=False,
... )  
[FieldmapEstimation(sources=<2 files>, method=<EstimatorType.ANAT: 5>,
                    bids_id='auto_00011'),
FieldmapEstimation(sources=<2 files>, method=<EstimatorType.ANAT: 5>,
                   bids_id='auto_00012')]

When the B0FieldIdentifier metadata is set for one or more fieldmaps, then the heuristics that use IntendedFor are dismissed:

>>> find_estimators(
...     layout=layouts['dsC'],
...     subject="01",
... )  
[FieldmapEstimation(sources=<5 files>, method=<EstimatorType.PEPOLAR: 2>,
                    bids_id='pepolar4pe')]

The only exception to the priority of B0FieldIdentifier is when fieldmaps are searched with the force_fmapless argument on:

>>> fm.clear_registry()  # Necessary as `pepolar4pe` is not changing.
>>> find_estimators(
...     layout=layouts['dsC'],
...     subject="01",
...     fmapless=True,
...     force_fmapless=True,
... )  
[FieldmapEstimation(sources=<5 files>, method=<EstimatorType.PEPOLAR: 2>,
                    bids_id='pepolar4pe'),
FieldmapEstimation(sources=<2 files>, method=<EstimatorType.ANAT: 5>,
                   bids_id='auto_00000')]