Skip to content

Commit 57f09b7

Browse files
authored
Merge pull request #190 from nipreps/add_trc_label
ENH: add tracer-label functionality for filtering
2 parents 133526d + a61d19b commit 57f09b7

File tree

3 files changed

+106
-0
lines changed

3 files changed

+106
-0
lines changed

petprep/cli/parser.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,13 @@ def _bids_filter(value, parser):
195195
help='A space delimited list of session identifiers or a single '
196196
'identifier (the ses- prefix can be removed)',
197197
)
198+
g_bids.add_argument(
199+
'--tracer-label',
200+
nargs='+',
201+
type=lambda label: label.removeprefix('trc-'),
202+
help='A space delimited list of tracer identifiers or a single '
203+
'identifier (the trc- prefix can be removed)',
204+
)
198205
# Re-enable when option is actually implemented
199206
# g_bids.add_argument('-r', '--run-id', action='store', default='single_run',
200207
# help='Select a specific run to be processed')
@@ -776,6 +783,13 @@ def parse_args(args=None, namespace=None):
776783
'session': config.execution.session_label,
777784
}
778785

786+
if config.execution.tracer_label:
787+
config.execution.bids_filters = config.execution.bids_filters or {}
788+
config.execution.bids_filters['pet'] = {
789+
**config.execution.bids_filters.get('pet', {}),
790+
'tracer': config.execution.tracer_label,
791+
}
792+
779793
pvc_vals = (opts.pvc_tool, opts.pvc_method, opts.pvc_psf)
780794
if any(val is not None for val in pvc_vals) and not all(val is not None for val in pvc_vals):
781795
parser.error('Options --pvc-tool, --pvc-method and --pvc-psf must be used together.')
@@ -946,5 +960,25 @@ def parse_args(args=None, namespace=None):
946960
f'{", ".join(sorted(missing_sessions))}.'
947961
)
948962

963+
if config.execution.tracer_label:
964+
tracer_filters = (
965+
config.execution.bids_filters.get('pet', {}) if config.execution.bids_filters else {}
966+
)
967+
tracer_filters = {key: value for key, value in tracer_filters.items() if key != 'tracer'}
968+
available_tracers = set(
969+
config.execution.layout.get(
970+
target='tracer',
971+
return_type='id',
972+
subject=list(participant_label) or None,
973+
**tracer_filters,
974+
)
975+
)
976+
missing_tracers = set(config.execution.tracer_label) - available_tracers
977+
if missing_tracers:
978+
parser.error(
979+
'One or more tracer labels were not found in the BIDS directory: '
980+
f'{", ".join(sorted(missing_tracers))}.'
981+
)
982+
949983
config.execution.participant_label = sorted(participant_label)
950984
config.workflow.skull_strip_template = config.workflow.skull_strip_template[0]

petprep/cli/tests/test_parser.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,76 @@ def test_session_label_only_filters_pet(tmp_path):
266266
_reset_config()
267267

268268

269+
def test_tracer_label_only_filters_pet(tmp_path):
270+
bids = tmp_path / 'bids'
271+
out_dir = tmp_path / 'out'
272+
work_dir = tmp_path / 'work'
273+
bids.mkdir()
274+
(bids / 'dataset_description.json').write_text('{"Name": "Test", "BIDSVersion": "1.8.0"}')
275+
276+
anat_path = bids / 'sub-01' / 'anat' / 'sub-01_T1w.nii.gz'
277+
anat_path.parent.mkdir(parents=True, exist_ok=True)
278+
nb.Nifti1Image(np.zeros((5, 5, 5)), np.eye(4)).to_filename(anat_path)
279+
280+
pet_path = bids / 'sub-01' / 'pet' / 'sub-01_trc-ucbj_pet.nii.gz'
281+
pet_path.parent.mkdir(parents=True, exist_ok=True)
282+
nb.Nifti1Image(np.zeros((5, 5, 5, 1)), np.eye(4)).to_filename(pet_path)
283+
(pet_path.with_suffix('').with_suffix('.json')).write_text(
284+
'{"FrameTimesStart": [0], "FrameDuration": [1]}'
285+
)
286+
287+
try:
288+
parse_args(
289+
args=[
290+
str(bids),
291+
str(out_dir),
292+
'participant',
293+
'--tracer-label',
294+
'ucbj',
295+
'--skip-bids-validation',
296+
'-w',
297+
str(work_dir),
298+
]
299+
)
300+
301+
filters = config.execution.bids_filters
302+
assert filters.get('pet', {}).get('tracer') == ['ucbj']
303+
assert 'tracer' not in filters.get('anat', {})
304+
finally:
305+
_reset_config()
306+
307+
308+
def test_tracer_label_validation(tmp_path):
309+
bids = tmp_path / 'bids'
310+
out_dir = tmp_path / 'out'
311+
work_dir = tmp_path / 'work'
312+
bids.mkdir()
313+
(bids / 'dataset_description.json').write_text('{"Name": "Test", "BIDSVersion": "1.8.0"}')
314+
315+
pet_path = bids / 'sub-01' / 'pet' / 'sub-01_trc-ucbj_pet.nii.gz'
316+
pet_path.parent.mkdir(parents=True, exist_ok=True)
317+
nb.Nifti1Image(np.zeros((5, 5, 5, 1)), np.eye(4)).to_filename(pet_path)
318+
(pet_path.with_suffix('').with_suffix('.json')).write_text(
319+
'{"FrameTimesStart": [0], "FrameDuration": [1]}'
320+
)
321+
322+
with pytest.raises(SystemExit):
323+
parse_args(
324+
args=[
325+
str(bids),
326+
str(out_dir),
327+
'participant',
328+
'--tracer-label',
329+
'dasb',
330+
'--skip-bids-validation',
331+
'-w',
332+
str(work_dir),
333+
]
334+
)
335+
336+
_reset_config()
337+
338+
269339
def test_pvc_argument_handling(tmp_path, minimal_bids):
270340
out_dir = tmp_path / 'out'
271341
work_dir = tmp_path / 'work'

petprep/config.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,8 @@ class execution(_Config):
434434
"""List of participant identifiers that are to be preprocessed."""
435435
session_label = None
436436
"""List of session identifiers that are to be preprocessed."""
437+
tracer_label = None
438+
"""List of tracer identifiers that are to be preprocessed."""
437439
task_id = None
438440
"""Select a particular task from all available in the dataset."""
439441
templateflow_home = _templateflow_home

0 commit comments

Comments
 (0)