diff --git a/fmriprep/cli/parser.py b/fmriprep/cli/parser.py index 1db70606..abc7025a 100644 --- a/fmriprep/cli/parser.py +++ b/fmriprep/cli/parser.py @@ -347,7 +347,7 @@ def _slice_time_ref(value, parser): action='store', nargs='+', default=[], - choices=['bbr', 'no-bbr', 'syn-sdc'], + choices=['bbr', 'no-bbr', 'syn-sdc', 'fmap-jacobian'], help='Force selected processing choices, overriding automatic selections ' '(a space delimited list).\n' ' * [no-]bbr: Use/disable boundary-based registration for BOLD-to-T1w coregistration\n' @@ -801,12 +801,20 @@ def parse_args(args=None, namespace=None): config.from_dict(vars(opts), init=['nipype']) # Consistency checks - if 'bbr' in config.workflow.force and 'no-bbr' in config.workflow.force: + force_set = set(config.workflow.force) + ignore_set = set(config.workflow.ignore) + if {'bbr', 'no-bbr'} <= force_set: msg = ( 'Cannot force and disable boundary-based registration at the same time. ' 'Remove `bbr` or `no-bbr` from the `--force` options.' ) raise ValueError(msg) + if 'fmap-jacobian' in force_set & ignore_set: + msg = ( + 'Cannot force and ignore fieldmap Jacobian correction. ' + 'Remove `fmap-jacobian` from either the `--force` or the `--ignore` option.' + ) + raise ValueError(msg) if not config.execution.notrack: import importlib.util diff --git a/fmriprep/workflows/base.py b/fmriprep/workflows/base.py index 9d1d81ae..8d174bb9 100644 --- a/fmriprep/workflows/base.py +++ b/fmriprep/workflows/base.py @@ -566,6 +566,7 @@ def init_single_subject_wf(subject_id: str): for field in ['fmap', 'fmap_ref', 'fmap_coeff', 'fmap_mask', 'fmap_id', 'sdc_method'] } + estimator_types = {est.bids_id: est.method for est in all_estimators} fmap_estimators = [] if all_estimators: # Find precomputed fieldmaps that apply to this workflow @@ -738,6 +739,15 @@ def init_single_subject_wf(subject_id: str): for bold_series in bold_runs: bold_file = bold_series[0] fieldmap_id = estimator_map.get(bold_file) + jacobian = False + + if fieldmap_id: + if 'fmap-jacobian' in config.workflow.force: + jacobian = True + elif 'fmap-jacobian' not in config.workflow.ignore: + # Default behavior is to only use Jacobians for PEPOLAR fieldmaps + est_type = estimator_types[fieldmap_id] + jacobian = est_type == est_type.__class__.PEPOLAR functional_cache = {} if config.execution.derivatives: @@ -758,6 +768,7 @@ def init_single_subject_wf(subject_id: str): bold_series=bold_series, precomputed=functional_cache, fieldmap_id=fieldmap_id, + jacobian=jacobian, ) if bold_wf is None: continue diff --git a/fmriprep/workflows/bold/base.py b/fmriprep/workflows/bold/base.py index 0130ebf6..060db8b0 100644 --- a/fmriprep/workflows/bold/base.py +++ b/fmriprep/workflows/bold/base.py @@ -57,6 +57,7 @@ def init_bold_wf( bold_series: list[str], precomputed: dict = None, fieldmap_id: str | None = None, + jacobian: bool = False, ) -> pe.Workflow: """ This workflow controls the functional preprocessing stages of *fMRIPrep*. @@ -253,6 +254,7 @@ def init_bold_wf( bold_series=bold_series, precomputed=precomputed, fieldmap_id=fieldmap_id, + jacobian=jacobian, omp_nthreads=omp_nthreads, ) @@ -292,6 +294,7 @@ def init_bold_wf( bold_native_wf = init_bold_native_wf( bold_series=bold_series, fieldmap_id=fieldmap_id, + jacobian=jacobian, omp_nthreads=omp_nthreads, ) @@ -383,7 +386,7 @@ def init_bold_wf( fieldmap_id=fieldmap_id if not multiecho else None, omp_nthreads=omp_nthreads, mem_gb=mem_gb, - jacobian='fmap-jacobian' not in config.workflow.ignore, + jacobian=jacobian, name='bold_anat_wf', ) bold_anat_wf.inputs.inputnode.resolution = 'native' @@ -443,7 +446,7 @@ def init_bold_wf( fieldmap_id=fieldmap_id if not multiecho else None, omp_nthreads=omp_nthreads, mem_gb=mem_gb, - jacobian='fmap-jacobian' not in config.workflow.ignore, + jacobian=jacobian, name='bold_std_wf', ) ds_bold_std_wf = init_ds_volumes_wf( @@ -550,7 +553,7 @@ def init_bold_wf( fieldmap_id=fieldmap_id if not multiecho else None, omp_nthreads=omp_nthreads, mem_gb=mem_gb, - jacobian='fmap-jacobian' not in config.workflow.ignore, + jacobian=jacobian, name='bold_MNI6_wf', ) diff --git a/fmriprep/workflows/bold/fit.py b/fmriprep/workflows/bold/fit.py index 1e315aac..737bf9fc 100644 --- a/fmriprep/workflows/bold/fit.py +++ b/fmriprep/workflows/bold/fit.py @@ -97,6 +97,7 @@ def init_bold_fit_wf( bold_series: list[str], precomputed: dict = None, fieldmap_id: str | None = None, + jacobian: bool = False, omp_nthreads: int = 1, name: str = 'bold_fit_wf', ) -> pe.Workflow: @@ -668,6 +669,7 @@ def init_bold_native_wf( *, bold_series: list[str], fieldmap_id: str | None = None, + jacobian: bool = False, omp_nthreads: int = 1, name: str = 'bold_native_wf', ) -> pe.Workflow: @@ -875,7 +877,7 @@ def init_bold_native_wf( # Resample to boldref boldref_bold = pe.Node( - ResampleSeries(jacobian='fmap-jacobian' not in config.workflow.ignore), + ResampleSeries(jacobian=jacobian), name='boldref_bold', n_procs=omp_nthreads, mem_gb=mem_gb['resampled'],