diff --git a/aslprep/interfaces/cbf.py b/aslprep/interfaces/cbf.py index 68c513e0a..d0410235c 100644 --- a/aslprep/interfaces/cbf.py +++ b/aslprep/interfaces/cbf.py @@ -426,6 +426,11 @@ class _ComputeCBFOutputSpec(TraitedSpec): None, desc="Arterial transit time map, in seconds. Only generated for multi-delay data.", ) + plds = traits.Either( + File(exists=True), + None, + desc="Post-labeling delays. Only defined if slice-timing correction is applied.", + ) class ComputeCBF(SimpleInterface): @@ -520,6 +525,7 @@ def _run_interface(self, runtime): m0data = np.mean(m0data, axis=0) scaled_m0data = m0_scale * m0data + self._results["plds"] = None if "SliceTiming" in metadata: # Offset PLD(s) by slice times # This step builds a voxel-wise array of post-labeling delay values, @@ -575,6 +581,7 @@ def _run_interface(self, runtime): newpath=runtime.cwd, ) pld_img.to_filename(pld_file) + self._results["plds"] = pld_file elif is_multi_pld: # Broadcast PLDs to voxels by PLDs diff --git a/aslprep/workflows/asl/cbf.py b/aslprep/workflows/asl/cbf.py index d668c94c1..633fc62af 100644 --- a/aslprep/workflows/asl/cbf.py +++ b/aslprep/workflows/asl/cbf.py @@ -1,6 +1,7 @@ # emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- # vi: set ft=python sts=4 ts=4 sw=4 et: """Workflows for calculating CBF.""" +import numpy as np import pandas as pd from nipype.interfaces import utility as niu from nipype.interfaces.fsl import Info, MultiImageMaths @@ -241,6 +242,7 @@ def init_compute_cbf_wf( "mean_cbf", "cbf_ts", # Only calculated for single-delay data "att", # Only calculated for multi-delay data + "plds", # SCORE/SCRUB outputs "cbf_ts_score", "mean_cbf_score", @@ -382,6 +384,7 @@ def _getfiledir(file): ("cbf_ts", "cbf_ts"), ("mean_cbf", "mean_cbf"), ("att", "att"), + ("plds", "plds"), ]), ]) # fmt:on @@ -465,10 +468,18 @@ def _getfiledir(file): basil_kwargs = {} if "SliceTiming" in metadata.keys(): - # This won't work for non-ascending slice orders. - basil_kwargs["slice_spacing"] = abs( - metadata["SliceTiming"][1] - metadata["SliceTiming"][0] - ) + slicetime_diffs = np.unique(np.diff(metadata["SliceTiming"])) + # Check if slice times are monotonic + monotonic_slicetimes = slicetime_diffs.size == 1 + # Check if slice times are ascending + ascending_slicetimes = np.all(slicetime_diffs > 0) + # Only set slicedt for ascending slice orders. + if monotonic_slicetimes and ascending_slicetimes: + basil_kwargs["slice_spacing"] = slicetime_diffs[0] + else: + config.loggers.interface.warning( + "Slice times are not ascending. They will be ignored in the BASIL call." + ) basilcbf = pe.Node( BASILCBF( diff --git a/pyproject.toml b/pyproject.toml index 2347a57de..b8dcca604 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,7 @@ dependencies = [ "pandas >= 0.24.0", "patsy", "psutil >= 5.4", - "pybids >= 0.13.2", + "pybids ~= 0.16.4", "pyyaml", "scipy == 1.10.1", # 1.11 introduces backwards incompatible change to scipy.stats.mode that doesn't work with bundled SDCFlows "sdcflows",