From cef3db06dbe63051832e6a77d953f2068a973030 Mon Sep 17 00:00:00 2001 From: Nikita Beliy Date: Fri, 15 Mar 2024 23:59:05 +0100 Subject: [PATCH] Added modality retrieval from path (#656) * Added modality retrieval from path * Moved get_modality to File * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * add tests and refactor * doc * refactor * ensure modality is passed --------- Co-authored-by: Beliy Nikita Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Remi Gau --- +bids/File.m | 42 ++++++++++++++++++++++--- tests/test_bids_file.m | 71 +++++++++++++++++++++++++++++++----------- 2 files changed, 91 insertions(+), 22 deletions(-) diff --git a/+bids/File.m b/+bids/File.m index 7742670a..c88fa2e1 100644 --- a/+bids/File.m +++ b/+bids/File.m @@ -205,6 +205,7 @@ obj.path = args.Results.input; end f_struct = bids.internal.parse_filename(args.Results.input); + obj.modality = obj.get_modality(f_struct.entities); elseif isstruct(args.Results.input) f_struct = args.Results.input; end @@ -223,14 +224,14 @@ obj.bids_file_error('emptySuffix', 'no suffix specified'); end - if isfield(f_struct, 'entities') - obj.entities = f_struct.entities; - end - if isfield(f_struct, 'modality') obj.modality = f_struct.modality; end + if isfield(f_struct, 'entities') + obj.entities = f_struct.entities; + end + if args.Results.use_schema obj = obj.use_schema(); end @@ -950,6 +951,39 @@ function validate_prefix(obj, prefix) end end + function modality = get_modality(obj, entities) + % Retrieves modality out of the path + % + % Only works if ses and sub entities match those found in the path + modality = ''; + + if isempty(obj.path) || isempty(fileparts(obj.path)) + return + end + + if ~isfield(entities, 'sub') + return + end + + path = fileparts(obj.path); + [path, candidate] = fileparts(path); + + has_ses = isfield(entities, 'ses') && ~isempty(entities.ses); + ses_ok = true; + if has_ses + [path, ses] = fileparts(path); + ses_ok = strcmp(ses, ['ses-' entities.ses]); + end + + [~, sub] = fileparts(path); + sub_ok = strcmp(sub, ['sub-' entities.sub]); + + if all([sub_ok, ses_ok]) + modality = candidate; + end + + end + end end diff --git a/tests/test_bids_file.m b/tests/test_bids_file.m index f7269ae4..ac70d0c2 100644 --- a/tests/test_bids_file.m +++ b/tests/test_bids_file.m @@ -30,6 +30,8 @@ bf = bids.File(file); + assertEqual(bf.modality, ''); + end function test_get_metadata_suffixes_basic() @@ -297,36 +299,69 @@ function test_forbidden_entity() function test_parsing() filename = 'wuasub-01_ses-test_task-faceRecognition_run-02_bold.nii'; - file = bids.File(filename, 'use_schema', false); + bf = bids.File(filename, 'use_schema', false); entities = struct('sub', '01', 'ses', 'test', ... 'task', 'faceRecognition', 'run', '02'); - assertEqual(file.prefix, 'wua'); - assertEqual(file.suffix, 'bold'); - assertEqual(file.extension, '.nii'); - assertEqual(file.entities, entities); - assertEqual(file.filename, 'wuasub-01_ses-test_task-faceRecognition_run-02_bold.nii'); - assertEqual(file.json_filename, 'wuasub-01_ses-test_task-faceRecognition_run-02_bold.json'); - assertEqual(file.bids_path, fullfile('sub-01', 'ses-test')); + assertEqual(bf.modality, ''); + assertEqual(bf.prefix, 'wua'); + assertEqual(bf.suffix, 'bold'); + assertEqual(bf.extension, '.nii'); + assertEqual(bf.entities, entities); + assertEqual(bf.filename, 'wuasub-01_ses-test_task-faceRecognition_run-02_bold.nii'); + assertEqual(bf.json_filename, 'wuasub-01_ses-test_task-faceRecognition_run-02_bold.json'); + assertEqual(bf.bids_path, fullfile('sub-01', 'ses-test')); filename = []; filename.prefix = 'wua'; filename.suffix = 'bold'; filename.ext = '.nii'; filename.entities = entities; - file = bids.File(filename, 'use_schema', false); - assertEqual(file.filename, 'wuasub-01_ses-test_task-faceRecognition_run-02_bold.nii'); + bf = bids.File(filename, 'use_schema', false); + assertEqual(bf.filename, 'wuasub-01_ses-test_task-faceRecognition_run-02_bold.nii'); + +end + +function test_modality_parsing() + + bf = bids.File(struct('modality', 'anat'), 'use_schema', false); + assertEqual(bf.modality, 'anat'); + + filename_expected = { ... + '', ''; ... + 'sub-01_task-faceRecognition_bold.nii', ''; ... + fullfile('foo', 'participants.tsv'), ''; ... + fullfile('sub-01', 'sub-01_scans.tsv'), ... + ''; ... % no modality folder + fullfile('sub-01', 'anat', 'sub-01_t1w.nii'), 'anat'; ... + fullfile('anat', 'sub-01_t1w.nii'), ... + ''; ... % no sub folder + fullfile('sub-01', 'ses-01', 'anat', 'sub-01_ses-01_t1w.nii'), 'anat'; ... + fullfile('ses-01', 'anat', 'sub-01_ses-01_t1w.nii'), ''; ... % no sub folder + fullfile('sub-01', 'ses-01', 'anat', 'sub-01_t1w.nii'), ... + ''; ... % no ses in filename + fullfile('sub-01', 'anat', 'sub-01_ses-01_t1w.nii'), '' ... % no ses folder + }; + + for i = 1:size(filename_expected) + bf = bids.File(filename_expected{i, 1}, 'use_schema', false); + assertEqual(bf.modality, filename_expected{i, 2}); + end + +end + +function test_parsing_empty_filename() + + bf = bids.File(''); - % testing empty file name - file = bids.File(''); - file.suffix = 'bold'; - file.extension = '.nii'; - assertEqual(file.filename, 'bold.nii'); + bf.suffix = 'bold'; + bf.extension = '.nii'; + assertEqual(bf.filename, 'bold.nii'); - file = file.set_entity('sub', 'abc'); - file.suffix = ''; - assertEqual(file.filename, 'sub-abc.nii'); + bf = bf.set_entity('sub', 'abc'); + bf.suffix = ''; + assertEqual(bf.filename, 'sub-abc.nii'); end