Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
9 changes: 5 additions & 4 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,6 @@ jobs:

# Inject pretend metadata
json_sidecar=/tmp/data/${DATASET}/task-mixedgamblestask_bold.json
awk 'NR==1{print; print " \"TotalReadoutTime\": 0.05,"} NR!=1' ${json_sidecar} > tmp && mv tmp ${json_sidecar}
awk 'NR==1{print; print " \"PhaseEncodingDirection\": \"j\","} NR!=1' ${json_sidecar} > tmp && mv tmp ${json_sidecar}

fmriprep-docker -i nipreps/fmriprep:latest \
Expand Down Expand Up @@ -530,7 +529,8 @@ jobs:
/tmp/data/${DATASET} /tmp/${DATASET}/fmriprep-partial participant \
--fs-subjects-dir /tmp/${DATASET}/freesurfer \
${FASTRACK_ARG} \
--sloppy --write-graph --use-syn-sdc --mem-mb 14336 \
--use-syn-sdc --fallback-total-readout-time 0.03125 \
--sloppy --write-graph --mem-mb 14336 \
--output-spaces MNI152NLin2009cAsym fsaverage5 fsnative MNI152NLin6Asym anat \
--nthreads 4 --cifti-output --project-goodvoxels -vv
- store_artifacts:
Expand Down Expand Up @@ -745,7 +745,7 @@ jobs:
# Inject pretend metadata for SDCFlows not to crash
# TODO / open question - do all echos need the metadata?
chmod +w /tmp/data/${DATASET}
echo '{"PhaseEncodingDirection": "j", "TotalReadoutTime": 0.058}' >> /tmp/data/${DATASET}/task-cuedSGT_bold.json
echo '{"PhaseEncodingDirection": "j"}' >> /tmp/data/${DATASET}/task-cuedSGT_bold.json
chmod -R -w /tmp/data/${DATASET}

fmriprep-docker -i nipreps/fmriprep:latest \
Expand All @@ -754,7 +754,8 @@ jobs:
/tmp/data/${DATASET} /tmp/${DATASET}/fmriprep participant \
${FASTRACK_ARG} \
--me-output-echos \
--fs-no-reconall --use-syn-sdc --ignore slicetiming \
--fs-no-reconall --ignore slicetiming \
--use-syn-sdc --fallback-total-readout-time 0.0625 \
--dummy-scans 1 --sloppy --write-graph \
--output-spaces MNI152NLin2009cAsym \
--mem-mb 14336 --nthreads 4 -vv
Expand Down
20 changes: 20 additions & 0 deletions fmriprep/cli/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,16 @@
raise parser.error(f'Slice time reference must be in range 0-1. Received {value}.')
return value

def _fallback_trt(value, parser):
if value == 'estimated':
return value
try:
return float(value)
except ValueError:
raise parser.error(

Check warning on line 158 in fmriprep/cli/parser.py

View check run for this annotation

Codecov / codecov/patch

fmriprep/cli/parser.py#L154-L158

Added lines #L154 - L158 were not covered by tests
f'Falling back to TRT must be a number or "estimated". Received {value}.'
) from None

verstr = f'fMRIPrep v{config.environment.version}'
currentv = Version(config.environment.version)
is_release = not any((currentv.is_devrelease, currentv.is_prerelease, currentv.is_postrelease))
Expand All @@ -163,6 +173,7 @@
PositiveInt = partial(_min_one, parser=parser)
BIDSFilter = partial(_bids_filter, parser=parser)
SliceTimeRef = partial(_slice_time_ref, parser=parser)
FallbackTRT = partial(_fallback_trt, parser=parser)

# Arguments as specified by BIDS-Apps
# required, positional arguments
Expand Down Expand Up @@ -417,6 +428,15 @@
type=int,
help='Number of nonsteady-state volumes. Overrides automatic detection.',
)
g_conf.add_argument(
'--fallback-total-readout-time',
required=False,
action='store',
default=None,
type=FallbackTRT,
help='Fallback value for Total Readout Time (TRT) calculation. '
'May be a number or "estimated".',
)
g_conf.add_argument(
'--random-seed',
dest='_random_seed',
Expand Down
3 changes: 3 additions & 0 deletions fmriprep/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,9 @@ class workflow(_Config):
"""Remove the mean from fieldmaps."""
force_syn = None
"""Run *fieldmap-less* susceptibility-derived distortions estimation."""
fallback_total_readout_time = None
"""Infer the total readout time if unavailable from authoritative metadata.
This may be a number or the string "estimated"."""
hires = None
"""Run FreeSurfer ``recon-all`` with the ``-hires`` flag."""
fs_no_resume = None
Expand Down
9 changes: 9 additions & 0 deletions fmriprep/interfaces/resampling.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,13 @@ def _run_interface(self, runtime):
class DistortionParametersInputSpec(TraitedSpec):
in_file = File(exists=True, desc='EPI image corresponding to the metadata')
metadata = traits.Dict(mandatory=True, desc='metadata corresponding to the inputs')
fallback = traits.Either(
None,
'estimated',
traits.Float,
usedefault=True,
desc='Fallback value for missing metadata',
)


class DistortionParametersOutputSpec(TraitedSpec):
Expand All @@ -215,6 +222,8 @@ def _run_interface(self, runtime):
self._results['readout_time'] = get_trt(
self.inputs.metadata,
self.inputs.in_file or None,
use_estimate=self.inputs.fallback == 'estimated',
fallback=self.inputs.fallback if isinstance(self.inputs.fallback, float) else None,
)
self._results['pe_direction'] = self.inputs.metadata['PhaseEncodingDirection']
except (KeyError, ValueError):
Expand Down
3 changes: 3 additions & 0 deletions fmriprep/workflows/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,10 @@ def init_single_subject_wf(subject_id: str):
from sdcflows import fieldmaps as fm
from sdcflows.workflows.base import init_fmap_preproc_wf

fallback_trt = config.workflow.fallback_total_readout_time
fmap_wf = init_fmap_preproc_wf(
use_metadata_estimates=fallback_trt == 'estimated',
fallback_total_readout_time=fallback_trt if isinstance(fallback_trt, float) else None,
debug='fieldmaps' in config.execution.debug,
estimators=fmap_estimators,
omp_nthreads=omp_nthreads,
Expand Down
6 changes: 5 additions & 1 deletion fmriprep/workflows/bold/apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def init_bold_volumetric_resample_wf(
metadata: dict,
mem_gb: dict[str, float],
jacobian: bool,
fallback_total_readout_time: str | float | None = None,
fieldmap_id: str | None = None,
omp_nthreads: int = 1,
name: str = 'bold_volumetric_resample_wf',
Expand Down Expand Up @@ -161,7 +162,10 @@ def init_bold_volumetric_resample_wf(
run_without_submitting=True,
)
distortion_params = pe.Node(
DistortionParameters(metadata=metadata),
DistortionParameters(
metadata=metadata,
fallback=fallback_total_readout_time,
),
name='distortion_params',
run_without_submitting=True,
)
Expand Down
1 change: 1 addition & 0 deletions fmriprep/workflows/bold/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ def init_bold_wf(
# Resample to anatomical space
bold_anat_wf = init_bold_volumetric_resample_wf(
metadata=all_metadata[0],
fallback_total_readout_time=config.workflow.fallback_total_readout_time,
fieldmap_id=fieldmap_id if not multiecho else None,
omp_nthreads=omp_nthreads,
mem_gb=mem_gb,
Expand Down
6 changes: 5 additions & 1 deletion fmriprep/workflows/bold/fit.py
Original file line number Diff line number Diff line change
Expand Up @@ -859,7 +859,11 @@ def init_bold_native_wf(
)

distortion_params = pe.Node(
DistortionParameters(metadata=metadata, in_file=bold_file),
DistortionParameters(
metadata=metadata,
in_file=bold_file,
fallback=config.workflow.fallback_total_readout_time,
),
name='distortion_params',
run_without_submitting=True,
)
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ dependencies = [
"psutil >= 5.4",
"pybids >= 0.16",
"requests >= 2.27",
"sdcflows >= 2.11.0",
"smriprep >= 0.17.0",
"sdcflows >= 2.13.0",
"smriprep >= 0.18.0",
"tedana >= 23.0.2",
"templateflow >= 24.2.2",
"transforms3d >= 0.4",
Expand Down
Loading