Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: Resample BOLD to fsLR directly, dropping fsaverage intermediate #3011

Merged
merged 21 commits into from
Jun 6, 2023
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
02e51c5
MNT: Pin master branches of nipreps dependencies
effigies May 18, 2023
70b93b9
ENH: Add several workbench commands
effigies May 12, 2023
972648a
ENH: Add GIFTI interface to generate ROI from thickness
effigies May 12, 2023
90621c2
ENH: Add fsLR resampling workflow
effigies May 17, 2023
4d03abf
RF: Remove goodvoxels from mri_vol2surf workflow
effigies May 17, 2023
9508e86
RF: Remove implicit fsaverage resampling from --cifti-output
effigies May 17, 2023
c2f4aff
RF: Remove cifti dependency on fsaverage workflow
effigies May 17, 2023
21e5c3b
ENH: Add OpenMPCommandMixin to enable n_procs
effigies May 18, 2023
7a42c27
DOCKER: Re-add git to main image to enable installing unstable depend…
effigies May 18, 2023
e071a4e
TEST: Copy test data folder and cd to temp path during interface doct…
effigies May 18, 2023
297d78e
FIX: Sort surfaces by basename, not full path
effigies May 19, 2023
68b6140
DOCTEST: Explicit normalize_whitespace for --pyargs friendliness
effigies May 19, 2023
47c7b28
FIX: Update sloppy/debug parameters in anatomical base workflow
mgxd Jun 2, 2023
64eecd6
CI: Update expected outputs
effigies Jun 2, 2023
a247fc2
Cleanup old comments and disjointed workflow connections
effigies Jun 5, 2023
606ed37
REPORT: Restore goodvoxels reporting, with slight clarification
effigies Jun 5, 2023
926a03b
ENH: Output goodvoxels mask (not constrained to ribbon)
effigies Jun 5, 2023
ee3ebc2
DOC: Update docs and workflow docstring
effigies Jun 5, 2023
63092fd
DOC: Clean up Sphinx warnings
effigies Jun 5, 2023
6e4e50e
FIX: Separate joinnode from outputnode
effigies Jun 6, 2023
3a3d9b4
CI: Expect goodvoxels mask
effigies Jun 6, 2023
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
8 changes: 6 additions & 2 deletions .circleci/ds005_bids_outputs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,23 @@ sub-01/anat/sub-01_from-MNI152NLin2009cAsym_to-T1w_mode-image_xfm.h5
sub-01/anat/sub-01_from-T1w_to-fsnative_mode-image_xfm.txt
sub-01/anat/sub-01_from-T1w_to-MNI152NLin2009cAsym_mode-image_xfm.h5
sub-01/anat/sub-01_hemi-L_curv.shape.gii
sub-01/anat/sub-01_hemi-L_desc-reg_sphere.surf.gii
sub-01/anat/sub-01_hemi-L_inflated.surf.gii
sub-01/anat/sub-01_hemi-L_midthickness.surf.gii
sub-01/anat/sub-01_hemi-L_pial.surf.gii
sub-01/anat/sub-01_hemi-L_smoothwm.surf.gii
sub-01/anat/sub-01_hemi-L_space-fsLR_desc-reg_sphere.surf.gii
sub-01/anat/sub-01_hemi-L_sulc.shape.gii
sub-01/anat/sub-01_hemi-L_thickness.shape.gii
sub-01/anat/sub-01_hemi-L_white.surf.gii
sub-01/anat/sub-01_hemi-R_curv.shape.gii
sub-01/anat/sub-01_hemi-R_desc-reg_sphere.surf.gii
sub-01/anat/sub-01_hemi-R_inflated.surf.gii
sub-01/anat/sub-01_hemi-R_midthickness.surf.gii
sub-01/anat/sub-01_hemi-R_pial.surf.gii
sub-01/anat/sub-01_hemi-R_smoothwm.surf.gii
sub-01/anat/sub-01_hemi-R_space-fsLR_desc-reg_sphere.surf.gii
sub-01/anat/sub-01_hemi-R_sulc.shape.gii
sub-01/anat/sub-01_hemi-R_thickness.shape.gii
sub-01/anat/sub-01_hemi-R_white.surf.gii
sub-01/anat/sub-01_label-CSF_probseg.nii.gz
sub-01/anat/sub-01_label-GM_probseg.nii.gz
sub-01/anat/sub-01_label-WM_probseg.nii.gz
Expand Down
8 changes: 6 additions & 2 deletions .circleci/ds005_legacy_outputs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,23 @@ fmriprep/sub-01/anat/sub-01_from-MNI152NLin2009cAsym_to-T1w_mode-image_xfm.h5
fmriprep/sub-01/anat/sub-01_from-T1w_to-fsnative_mode-image_xfm.txt
fmriprep/sub-01/anat/sub-01_from-T1w_to-MNI152NLin2009cAsym_mode-image_xfm.h5
fmriprep/sub-01/anat/sub-01_hemi-L_curv.shape.gii
fmriprep/sub-01/anat/sub-01_hemi-L_desc-reg_sphere.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-L_inflated.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-L_midthickness.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-L_pial.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-L_smoothwm.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-L_space-fsLR_desc-reg_sphere.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-L_sulc.shape.gii
fmriprep/sub-01/anat/sub-01_hemi-L_thickness.shape.gii
fmriprep/sub-01/anat/sub-01_hemi-L_white.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-R_curv.shape.gii
fmriprep/sub-01/anat/sub-01_hemi-R_desc-reg_sphere.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-R_inflated.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-R_midthickness.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-R_pial.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-R_smoothwm.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-R_space-fsLR_desc-reg_sphere.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-R_sulc.shape.gii
fmriprep/sub-01/anat/sub-01_hemi-R_thickness.shape.gii
fmriprep/sub-01/anat/sub-01_hemi-R_white.surf.gii
fmriprep/sub-01/anat/sub-01_label-CSF_probseg.nii.gz
fmriprep/sub-01/anat/sub-01_label-GM_probseg.nii.gz
fmriprep/sub-01/anat/sub-01_label-WM_probseg.nii.gz
Expand Down
8 changes: 6 additions & 2 deletions .circleci/ds005_legacy_partial_outputs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,23 @@ fmriprep/sub-01/anat/sub-01_from-T1w_to-fsnative_mode-image_xfm.txt
fmriprep/sub-01/anat/sub-01_from-T1w_to-MNI152NLin2009cAsym_mode-image_xfm.h5
fmriprep/sub-01/anat/sub-01_from-T1w_to-MNI152NLin6Asym_mode-image_xfm.h5
fmriprep/sub-01/anat/sub-01_hemi-L_curv.shape.gii
fmriprep/sub-01/anat/sub-01_hemi-L_desc-reg_sphere.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-L_inflated.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-L_midthickness.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-L_pial.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-L_smoothwm.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-L_space-fsLR_desc-reg_sphere.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-L_sulc.shape.gii
fmriprep/sub-01/anat/sub-01_hemi-L_thickness.shape.gii
fmriprep/sub-01/anat/sub-01_hemi-L_white.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-R_curv.shape.gii
fmriprep/sub-01/anat/sub-01_hemi-R_desc-reg_sphere.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-R_inflated.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-R_midthickness.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-R_pial.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-R_smoothwm.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-R_space-fsLR_desc-reg_sphere.surf.gii
fmriprep/sub-01/anat/sub-01_hemi-R_sulc.shape.gii
fmriprep/sub-01/anat/sub-01_hemi-R_thickness.shape.gii
fmriprep/sub-01/anat/sub-01_hemi-R_white.surf.gii
fmriprep/sub-01/anat/sub-01_label-CSF_probseg.nii.gz
fmriprep/sub-01/anat/sub-01_label-GM_probseg.nii.gz
fmriprep/sub-01/anat/sub-01_label-WM_probseg.nii.gz
Expand Down
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ RUN apt-get update && \
bc \
ca-certificates \
curl \
git \
gnupg \
lsb-release \
netbase \
Expand Down
1 change: 0 additions & 1 deletion fmriprep/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,6 @@ def init_spaces(checkpoint=True):
if cifti_output:
# CIFTI grayordinates to corresponding FSL-MNI resolutions.
vol_res = "2" if cifti_output == "91k" else "1"
spaces.add(Reference("fsaverage", {"den": "164k"}))
spaces.add(Reference("MNI152NLin6Asym", {"res": vol_res}))

# Make the SpatialReferences object available
Expand Down
9 changes: 0 additions & 9 deletions fmriprep/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,6 @@
os.environ['NO_ET'] = '1'


def chdir_or_skip():
data_dir = ir_files('fmriprep') / 'data'
try:
os.chdir(data_dir)
except OSError:
pytest.skip(f"Cannot chdir into {data_dir!r}. Probably in a zipped distribution.")


def copytree_or_skip(source, target):
data_dir = ir_files('fmriprep') / source
if not data_dir.exists():
Expand All @@ -36,7 +28,6 @@ def copytree_or_skip(source, target):

@pytest.fixture(autouse=True)
def populate_namespace(doctest_namespace, tmp_path):
doctest_namespace['chdir_or_skip'] = chdir_or_skip
doctest_namespace['copytree_or_skip'] = copytree_or_skip
doctest_namespace['testdir'] = tmp_path

Expand Down
16 changes: 0 additions & 16 deletions fmriprep/interfaces/confounds.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,14 +207,6 @@ class GatherConfounds(SimpleInterface):
r"""
Combine various sources of confounds in one TSV file

.. testsetup::

>>> from tempfile import TemporaryDirectory
>>> tmpdir = TemporaryDirectory()
>>> os.chdir(tmpdir.name)

.. doctest::

>>> pd.DataFrame({'a': [0.1]}).to_csv('signals.tsv', index=False, na_rep='n/a')
>>> pd.DataFrame({'b': [0.2]}).to_csv('dvars.tsv', index=False, na_rep='n/a')

Expand All @@ -230,10 +222,6 @@ class GatherConfounds(SimpleInterface):
a b
0 0.1 0.2

.. testcleanup::

>>> tmpdir.cleanup()

"""
input_spec = GatherConfoundsInputSpec
output_spec = GatherConfoundsOutputSpec
Expand Down Expand Up @@ -274,9 +262,6 @@ def _gather_confounds(
Load confounds from the filenames, concatenate together horizontally
and save new file.

>>> from tempfile import TemporaryDirectory
>>> tmpdir = TemporaryDirectory()
>>> os.chdir(tmpdir.name)
>>> pd.DataFrame({'Global Signal': [0.1]}).to_csv('signals.tsv', index=False, na_rep='n/a')
>>> pd.DataFrame({'stdDVARS': [0.2]}).to_csv('dvars.tsv', index=False, na_rep='n/a')
>>> out_file, confound_list = _gather_confounds('signals.tsv', 'dvars.tsv')
Expand All @@ -287,7 +272,6 @@ def _gather_confounds(
... engine='python') # doctest: +NORMALIZE_WHITESPACE
global_signal std_dvars
0 0.1 0.2
>>> tmpdir.cleanup()


"""
Expand Down
40 changes: 40 additions & 0 deletions fmriprep/interfaces/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from pathlib import Path
from shutil import copytree

import pytest

try:
from contextlib import chdir as _chdir
except ImportError: # PY310
import os
from contextlib import contextmanager

@contextmanager # type: ignore
def _chdir(path):
cwd = os.getcwd()
os.chdir(path)
try:
yield
finally:
os.chdir(cwd)


@pytest.fixture(scope="module")
def data_dir():
return Path(__file__).parent / "tests" / "data"


@pytest.fixture(autouse=True)
def _docdir(request, tmp_path):
# Trigger ONLY for the doctests.
doctest_plugin = request.config.pluginmanager.getplugin("doctest")
if isinstance(request.node, doctest_plugin.DoctestItem):
copytree(Path(__file__).parent / "tests" / "data", tmp_path, dirs_exist_ok=True)

# Chdir only for the duration of the test.
with _chdir(tmp_path):
yield

else:
# For normal tests, we have to yield, since this is a yield-fixture.
yield
65 changes: 65 additions & 0 deletions fmriprep/interfaces/gifti.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
# vi: set ft=python sts=4 ts=4 sw=4 et:
"""Interfaces for manipulating GIFTI files."""
import os

import nibabel as nb
import numpy as np
from nipype.interfaces.base import File, SimpleInterface, TraitedSpec, isdefined, traits
from nipype.utils.filemanip import fname_presuffix


class CreateROIInputSpec(TraitedSpec):
subject_id = traits.Str(desc='subject ID')
hemisphere = traits.Enum(
"L",
"R",
mandatory=True,
desc='hemisphere',
)
thickness_file = File(exists=True, mandatory=True, desc='input GIFTI file')


class CreateROIOutputSpec(TraitedSpec):
roi_file = File(desc='output GIFTI file')


class CreateROI(SimpleInterface):
"""Prepare GIFTI shape file for use in"""

input_spec = CreateROIInputSpec
output_spec = CreateROIOutputSpec

def _run_interface(self, runtime):
subject, hemi = self.inputs.subject_id, self.inputs.hemisphere
if not isdefined(subject):
subject = 'sub-XYZ'
img = nb.GiftiImage.from_filename(self.inputs.thickness_file)
# wb_command -set-structure
img.meta["AnatomicalStructurePrimary"] = {'L': 'CortexLeft', 'R': 'CortexRight'}[hemi]
darray = img.darrays[0]
# wb_command -set-map-names
meta = darray.meta
meta['Name'] = f"{subject}_{hemi}_ROI"
# wb_command -metric-palette calls have no effect on ROI files

# Compiling an odd sequence of math operations that works out to:
# wb_command -metric-math "abs(var * -1) > 0"
roi = np.abs(darray.data) > 0

darray = nb.gifti.GiftiDataArray(
roi,
intent=darray.intent,
datatype=darray.datatype,
encoding=darray.encoding,
endian=darray.endian,
coordsys=darray.coordsys,
ordering=darray.ind_ord,
meta=meta,
)

out_filename = os.path.join(runtime.cwd, f"{subject}.{hemi}.roi.native.shape.gii")
img.to_filename(out_filename)
self._results["roi_file"] = out_filename
return runtime
Loading