sdcflows.utils.wrangler module#

Find fieldmaps on the BIDS inputs for SDC.

sdcflows.utils.wrangler.find_anatomical_estimators(*, anat_file: BIDSFile, layout: BIDSLayout, subject: str, sessions: List[str], base_entities: Dict[str, Any], suffixes: List[str]) List[List[FieldmapFile]][source]#

Find anatomical estimators

Given an anatomical reference image, create lists of files for estimating susceptibility distortion for the EPI images in a dataset.

Parameters:
  • anat_file (bids.layout.BIDSFile) – Anatomical reference image to use in estimators.

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

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

  • sessions (list) – One of more session identifiers. To use all, pass [None].

  • base_entities (dict) – Entities to use to query for images. These should include any filters.

  • suffixes (list) – EPI suffixes, for example ["bold", "dwi", "asl"]. Associated "sbref"s will be found and used in place of BOLD/diffusion EPIs. Similarly, "m0scan"s associated with ASL runs with the IntendedFor or B0FieldIdentifier metadata will be used in place of ASL runs.

sdcflows.utils.wrangler.find_estimators(*, layout: BIDSLayout, subject: str, sessions: List[str] | None = None, fmapless: bool | set = True, force_fmapless: bool = False, logger: Logger | None = None, bids_filters: dict | None = None, anat_suffix: str | List[str] = 'T1w') 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 suffixes for EPI images (namely, "dwi", "bold", "asl", or "sbref"). When fmapless is True, heuristics will use the {"bold", "dwi", "asl"} 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.

  • anat_suffix (str or list) – String or list of strings to filter anatomical images for fieldmap-less approaches. If not provided, T1w is used.

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'),
 FieldmapEstimation(sources=<2 files>, method=<EstimatorType.PEPOLAR: 2>,
                    bids_id='auto_00008')]

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_...'),
 FieldmapEstimation(sources=<2 files>, method=<EstimatorType.ANAT: 5>,
                    bids_id='auto_...'),
 FieldmapEstimation(sources=<2 files>, method=<EstimatorType.ANAT: 5>,
                    bids_id='auto_...')]

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_...'),
FieldmapEstimation(sources=<2 files>, method=<EstimatorType.ANAT: 5>,
                   bids_id='auto_...'),
FieldmapEstimation(sources=<2 files>, method=<EstimatorType.ANAT: 5>,
                   bids_id='auto_...'),
FieldmapEstimation(sources=<2 files>, method=<EstimatorType.ANAT: 5>,
                   bids_id='auto_...'),
FieldmapEstimation(sources=<2 files>, method=<EstimatorType.ANAT: 5>,
                   bids_id='auto_...'),
FieldmapEstimation(sources=<2 files>, method=<EstimatorType.ANAT: 5>,
                   bids_id='auto_...'),
FieldmapEstimation(sources=<2 files>, method=<EstimatorType.ANAT: 5>,
                   bids_id='auto_...'),
FieldmapEstimation(sources=<2 files>, method=<EstimatorType.ANAT: 5>,
                   bids_id='auto_...'),
FieldmapEstimation(sources=<2 files>, method=<EstimatorType.ANAT: 5>,
                   bids_id='auto_...')]

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_...'),
FieldmapEstimation(sources=<2 files>, method=<EstimatorType.ANAT: 5>,
                   bids_id='auto_...')]

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_...')]