Skip to content

Support session-wise anatomical processing #479

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

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
18 changes: 17 additions & 1 deletion src/smriprep/utils/bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,14 @@
import smriprep


def collect_derivatives(derivatives_dir, subject_id, std_spaces, spec=None, patterns=None):
def collect_derivatives(
derivatives_dir,
subject_id,
std_spaces,
spec=None,
patterns=None,
session_id=None,
):
"""Gather existing derivatives and compose a cache."""
if spec is None or patterns is None:
_spec, _patterns = tuple(loads(smriprep.load_data('io_spec.json').read_text()).values())
Expand All @@ -47,6 +54,9 @@ def collect_derivatives(derivatives_dir, subject_id, std_spaces, spec=None, patt
derivs_cache = {}
for key, qry in spec['baseline'].items():
qry['subject'] = subject_id
if session_id:
qry['session'] = session_id

item = layout.get(return_type='filename', **qry)
if not item:
continue
Expand All @@ -59,6 +69,9 @@ def collect_derivatives(derivatives_dir, subject_id, std_spaces, spec=None, patt
for key, qry in spec['transforms'].items():
qry = qry.copy()
qry['subject'] = subject_id
if session_id:
qry['session'] = session_id

qry['from'] = qry['from'] or space
qry['to'] = qry['to'] or space
item = layout.get(return_type='filename', **qry)
Expand All @@ -68,6 +81,9 @@ def collect_derivatives(derivatives_dir, subject_id, std_spaces, spec=None, patt

for key, qry in spec['surfaces'].items():
qry['subject'] = subject_id
if session_id:
qry['session'] = session_id

item = layout.get(return_type='filename', **qry)
if not item or len(item) != 2:
continue
Expand Down
46 changes: 34 additions & 12 deletions src/smriprep/workflows/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def init_smriprep_wf(
skull_strip_fixed_seed,
skull_strip_template,
spaces,
subject_list,
subworkflows_list,
work_dir,
bids_filters,
cifti_output,
Expand Down Expand Up @@ -102,7 +102,7 @@ def init_smriprep_wf(
skull_strip_mode='force',
skull_strip_template=Reference('OASIS30ANTs'),
spaces=spaces,
subject_list=['smripreptest'],
subworkflows_list=[('smripreptest', None)],
work_dir='.',
bids_filters=None,
cifti_output=None,
Expand Down Expand Up @@ -148,8 +148,8 @@ def init_smriprep_wf(
Spatial reference to use in atlas-based brain extraction.
spaces : :py:class:`~niworkflows.utils.spaces.SpatialReferences`
Object containing standard and nonstandard space specifications.
subject_list : :obj:`list`
List of subject labels
subworkflows_list : :obj:`list` of :obj:`tuple`
List of subject-session label pairs
work_dir : :obj:`str`
Directory in which to store workflow execution state and
temporary files
Expand All @@ -174,7 +174,17 @@ def init_smriprep_wf(
if fs_subjects_dir is not None:
fsdir.inputs.subjects_dir = str(fs_subjects_dir.absolute())

for subject_id in subject_list:
for subject_id, session_ids in subworkflows_list:
ses_str = session_ids
if not isinstance(session_ids, (str, type(None))):
ses_str = '_'.join(session_ids)

name = (
f'single_subject_{subject_id}_{ses_str}_wf'
if session_ids
else f'single_subject_{subject_id}_wf'
)

single_subject_wf = init_single_subject_wf(
sloppy=sloppy,
debug=debug,
Expand All @@ -186,14 +196,15 @@ def init_smriprep_wf(
longitudinal=longitudinal,
low_mem=low_mem,
msm_sulc=msm_sulc,
name=f'single_subject_{subject_id}_wf',
name=name,
omp_nthreads=omp_nthreads,
output_dir=output_dir,
skull_strip_fixed_seed=skull_strip_fixed_seed,
skull_strip_mode=skull_strip_mode,
skull_strip_template=skull_strip_template,
spaces=spaces,
subject_id=subject_id,
session_id=session_ids,
bids_filters=bids_filters,
cifti_output=cifti_output,
)
Expand Down Expand Up @@ -231,6 +242,7 @@ def init_single_subject_wf(
skull_strip_template,
spaces,
subject_id,
session_id,
bids_filters,
cifti_output,
):
Expand All @@ -241,8 +253,8 @@ def init_single_subject_wf(
It collects and reports information about the subject, and prepares
sub-workflows to perform anatomical and functional preprocessing.

Anatomical preprocessing is performed in a single workflow, regardless of
the number of sessions.
Anatomical preprocessing is typically performed in a single workflow,
regardless of the number of sessions, unless the session_id parameter is provided.
Functional preprocessing is performed using a separate workflow for each
individual BOLD series.

Expand Down Expand Up @@ -276,6 +288,7 @@ def init_single_subject_wf(
skull_strip_template=Reference('OASIS30ANTs'),
spaces=spaces,
subject_id='test',
session_id=None,
bids_filters=None,
cifti_output=None,
)
Expand Down Expand Up @@ -320,7 +333,9 @@ def init_single_subject_wf(
spaces : :py:class:`~niworkflows.utils.spaces.SpatialReferences`
Object containing standard and nonstandard space specifications.
subject_id : :obj:`str`
List of subject labels
Subject label
session_id : :obj:`str` or None
Session label
bids_filters : dict
Provides finer specification of the pipeline input files through pybids entities filters.
A dict with the following structure {<suffix>:{<entity>:<filter>,...},...}
Expand Down Expand Up @@ -375,7 +390,9 @@ def init_single_subject_wf(
std_spaces = spaces.get_spaces(nonstandard=False, dim=(3,))
std_spaces.append('fsnative')
for deriv_dir in derivatives:
deriv_cache.update(collect_derivatives(deriv_dir, subject_id, std_spaces))
deriv_cache.update(
collect_derivatives(deriv_dir, subject_id, std_spaces, session_id=session_id)
)

inputnode = pe.Node(niu.IdentityInterface(fields=['subjects_dir']), name='inputnode')

Expand All @@ -397,10 +414,15 @@ def init_single_subject_wf(
run_without_submitting=True,
)

if session_id is not None:
dismiss_entities = None
else:
dismiss_entities = ('session',)

ds_report_summary = pe.Node(
DerivativesDataSink(
base_directory=output_dir,
dismiss_entities=('session',),
dismiss_entities=dismiss_entities,
desc='summary',
datatype='figures',
),
Expand All @@ -411,7 +433,7 @@ def init_single_subject_wf(
ds_report_about = pe.Node(
DerivativesDataSink(
base_directory=output_dir,
dismiss_entities=('session',),
dismiss_entities=dismiss_entities,
desc='about',
datatype='figures',
),
Expand Down
Loading