Skip to content

Commit

Permalink
[ENH] add electrodes and optodes as group dependencies (bids-standard…
Browse files Browse the repository at this point in the history
…#586)

* add electrodes and optodes as dependencies

* inline function

* fix
  • Loading branch information
Remi-Gau authored Jun 18, 2023
1 parent 07897c5 commit 1faff9b
Show file tree
Hide file tree
Showing 16 changed files with 138 additions and 126 deletions.
40 changes: 40 additions & 0 deletions +bids/layout.m
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,8 @@

file_list = return_file_list(modality, subject, schema);

electrode_tsv = list_electrodes(modality, file_list);

% dependency previous file
previous = struct('group', struct('index', 0, 'base', '', 'len', 1), ...
'data', struct('index', 0, 'base', '', 'len', 1), ...
Expand Down Expand Up @@ -440,6 +442,9 @@

subject.(modality)(end) = manage_M0(subject.perf(end), pth, verbose);

case {'eeg', 'ieeg', 'nirs'}
subject = appent_electrodes(subject, modality, electrode_tsv);

end

end
Expand All @@ -450,6 +455,39 @@

end

function electrode_tsv = list_electrodes(modality, file_list)

electrode_tsv = {};

switch modality
case {'eeg', 'ieeg'}
suffix = 'electrodes';
case {'nirs'}
suffix = 'optodes';
otherwise
return
end

is_electrode_tsv = ~cellfun('isempty', ...
strfind(file_list, ['_' suffix '.tsv']));
has_electrode_tsv = any(is_electrode_tsv);
if has_electrode_tsv
electrode_tsv = file_list(is_electrode_tsv);
end

end

function subject = appent_electrodes(subject, modality, electrode_tsv)
for i = 1:numel(electrode_tsv)
pth = fullfile(subject.path, modality);
fullpath_filename = fullfile(pth, electrode_tsv{i});
if ~ismember(fullpath_filename, ...
subject.(modality)(end).dependencies.group)
subject.(modality)(end).dependencies.group{end + 1, 1} = fullpath_filename;
end
end
end

function BIDS = validate_description(BIDS, tolerant, verbose)

if ~exist(fullfile(BIDS.pth, 'dataset_description.json'), 'file')
Expand Down Expand Up @@ -578,6 +616,8 @@
% This groups file that logically need each other,
% like functional mri and events tabular file.
% It also takes care of fmap magnitude1/2 and phasediff.
% This will also include files that are shared across
% several runs (i.e electrodes.tsv)

pth = fullfile(subject.path, modality);
fullpath_filename = fullfile(pth, file);
Expand Down
86 changes: 24 additions & 62 deletions tests/tests_query/test_bids_query.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,19 @@

function test_query_participants()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'pet002'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'pet002'));

participants = bids.query(BIDS, 'participants');

BIDS = bids.layout(fullfile(pth_bids_example, 'asl001'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'asl001'));

participants = bids.query(BIDS, 'participants');

end

function test_query_impossible_suffix_should_return_empty()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'synthetic'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'synthetic'));

% no suffix bold in anat
filter = struct('sub', '01', ...
Expand All @@ -40,14 +36,12 @@ function test_query_impossible_suffix_should_return_empty()

function test_query_suffixes()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'pet002'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'pet002'));

suffixes = {'T1w', 'pet'};
assertEqual(bids.query(BIDS, 'suffixes'), suffixes);

BIDS = bids.layout(fullfile(pth_bids_example, 'synthetic'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'synthetic'));

suffixes = {'T1w'};
assertEqual(bids.query(BIDS, 'suffixes', 'modality', 'anat'), suffixes);
Expand All @@ -56,9 +50,7 @@ function test_query_suffixes()

function test_query_subjects()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'ieeg_visual'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'ieeg_visual'));

subjs = arrayfun(@(x) sprintf('%02d', x), 1:2, 'UniformOutput', false);
assertEqual(bids.query(BIDS, 'subjects'), subjs);
Expand Down Expand Up @@ -93,9 +85,7 @@ function test_query_regex_subjects_no_regex_by_default()

function test_query_regex_subjects()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'ds000247'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'ds000247'));

data = bids.query(BIDS, 'data', 'sub', '.*', 'suffix', 'T1w');

Expand All @@ -109,9 +99,7 @@ function test_query_regex_subjects()

function test_query_with_indices()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'ds105'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'ds105'));

data_1 = bids.query(BIDS, 'data', 'sub', '1', 'run', {3, 5, '7', '01'}, 'suffix', 'bold');
data_2 = bids.query(BIDS, 'data', 'sub', '1', 'run', 1:2:7, 'suffix', 'bold');
Expand All @@ -122,9 +110,7 @@ function test_query_with_indices()

function test_query_entities()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'qmri_qsm'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'qmri_qsm'));

entities = bids.query(BIDS, 'entities');

Expand All @@ -134,7 +120,7 @@ function test_query_entities()
assertEqual(entities, expected);

%%
BIDS = bids.layout(fullfile(pth_bids_example, 'pet002'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'pet002'));

entities = bids.query(BIDS, 'entities', 'suffix', 'pet');

Expand All @@ -147,24 +133,20 @@ function test_query_entities()

function test_query_events_tsv_in_root()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'synthetic'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'synthetic'));

data = bids.query(BIDS, 'data', 'sub', '01', 'ses', '01', 'task', 'nback', 'suffix', 'events');

assertEqual(data, ...
{bids.internal.file_utils(fullfile(pth_bids_example, ...
{bids.internal.file_utils(fullfile(get_test_data_dir(), ...
'synthetic', ...
'task-nback_events.tsv'), 'cpath')});

end

function test_query_exclude_entity()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'ds000246'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'ds000246'));

filter = struct('sub', '0001');
assertEqual(bids.query(BIDS, 'modalities', filter), {'anat', 'meg'});
Expand All @@ -183,9 +165,7 @@ function test_query_exclude_entity()

function test_query_basic()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'pet005'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'pet005'));

tasks = {'eyes'};
assertEqual(bids.query(BIDS, 'tasks'), tasks);
Expand All @@ -200,9 +180,7 @@ function test_query_basic()

function test_query_data_filter()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'pet005'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'pet005'));

% make sure that query can work with filter
filters = {'sub', {'01'}; ...
Expand All @@ -223,9 +201,7 @@ function test_query_data_filter()

function test_query_extension()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'qmri_tb1tfl'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'qmri_tb1tfl'));

extensions = bids.query(BIDS, 'extensions');

Expand All @@ -244,9 +220,7 @@ function test_query_extension()

function test_query_metadata()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'qmri_tb1tfl'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'qmri_tb1tfl'));

md = bids.query(BIDS, 'metadata', ...
'sub', '01', ...
Expand All @@ -260,9 +234,7 @@ function test_query_metadata()

function test_query_modalities()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'pet002'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'pet002'));

modalities = {'anat', 'pet'};

Expand All @@ -274,9 +246,7 @@ function test_query_modalities()

function test_query_tsv_content()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'eeg_ds003645s_hed_inheritance'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'eeg_ds003645s_hed_inheritance'));

tsv_content = bids.query(BIDS, 'tsv_content', 'suffix', 'events');

Expand All @@ -297,34 +267,28 @@ function test_query_tsv_content()

function test_query_tsv_content_error()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'qmri_tb1tfl'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'qmri_tb1tfl'));
assertExceptionThrown(@()bids.query(BIDS, 'tsv_content', 'extension', '.nii.gz'), ...
'query:notJustTsvFiles');

end

function test_query_sessions()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'synthetic'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'synthetic'));
sessions = {'01', '02'};
assertEqual(bids.query(BIDS, 'sessions'), sessions);
assertEqual(bids.query(BIDS, 'sessions', 'sub', '02'), sessions);

BIDS = bids.layout(fullfile(pth_bids_example, 'qmri_tb1tfl'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'qmri_tb1tfl'));

assert(isempty(bids.query(BIDS, 'sessions')));

end

function test_query_sessions_tsv()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'synthetic'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'synthetic'));

suffixes = bids.query(BIDS, 'suffixes');
assert(ismember('sessions', suffixes));
Expand Down Expand Up @@ -366,9 +330,7 @@ function test_query_sessions_tsv()

function test_query_scans_tsv()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'motion_spotrotation'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'motion_spotrotation'));

suffixes = bids.query(BIDS, 'suffixes');
assert(ismember('scans', suffixes));
Expand Down
16 changes: 4 additions & 12 deletions tests/tests_query/test_bids_query_asl.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@

function test_bids_query_asl_basic_asl002()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'asl002'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'asl002'));

modalities = {'anat', 'perf'};
assertEqual(bids.query(BIDS, 'modalities'), modalities);
Expand All @@ -37,9 +35,7 @@ function test_bids_query_asl_basic_asl002()

function test_bids_query_asl_basic_asl001()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'asl001'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'asl001'));

modalities = {'anat', 'perf'};
assertEqual(bids.query(BIDS, 'modalities'), modalities);
Expand Down Expand Up @@ -68,9 +64,7 @@ function test_bids_query_asl_basic_asl001()

function test_bids_query_asl_basic_asl003()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'asl003'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'asl003'));

modalities = {'anat', 'perf'};
assertEqual(bids.query(BIDS, 'modalities'), modalities);
Expand All @@ -82,9 +76,7 @@ function test_bids_query_asl_basic_asl003()

function test_bids_query_asl_basic_asl004()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'asl004'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'asl004'));

modalities = {'anat', 'fmap', 'perf'};
assertEqual(bids.query(BIDS, 'modalities'), modalities);
Expand Down
4 changes: 1 addition & 3 deletions tests/tests_query/test_bids_query_derivatives.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@

function test_bids_query_derivatives_basic()

pth_bids_example = get_test_data_dir();

BIDS = bids.layout(fullfile(pth_bids_example, 'ds000001-fmriprep'), ...
BIDS = bids.layout(fullfile(get_test_data_dir(), 'ds000001-fmriprep'), ...
'use_schema', false);

spaces = bids.query(BIDS, 'spaces');
Expand Down
5 changes: 1 addition & 4 deletions tests/tests_query/test_bids_query_dwi.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,8 @@ function test_bids_query_dwi_basic()
%
% dwi queries
%

pth_bids_example = get_test_data_dir();

%%
BIDS = bids.layout(fullfile(pth_bids_example, 'eeg_rest_fmri'));
BIDS = bids.layout(fullfile(get_test_data_dir(), 'eeg_rest_fmri'));

modalities = {'anat', 'dwi', 'eeg', 'func'};
assertEqual(bids.query(BIDS, 'modalities'), modalities);
Expand Down
Loading

0 comments on commit 1faff9b

Please sign in to comment.