From 9ff5d24d5fb023d9fc255fd54c7990ab7edd7b27 Mon Sep 17 00:00:00 2001 From: Ceren Date: Mon, 27 Jul 2020 19:00:57 +0100 Subject: [PATCH 01/22] function name fix --- tests/testmanual_makeRawDataset.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testmanual_makeRawDataset.m b/tests/testmanual_makeRawDataset.m index ce176a41..fa0cbe2e 100644 --- a/tests/testmanual_makeRawDataset.m +++ b/tests/testmanual_makeRawDataset.m @@ -1,4 +1,4 @@ -function test_makeRawDataset() +function testmanual_makeRawDataset() fprintf('\n\n--------------------------------------------------------------------\n\n'); From c2ac97f8a1aa7310c2debc2213fda1320820fcf6 Mon Sep 17 00:00:00 2001 From: Ceren Date: Mon, 27 Jul 2020 21:14:20 +0100 Subject: [PATCH 02/22] expParams to cfg --- checkCFG.m | 26 ++++---- convertSourceToRaw.m | 6 +- createBoldJson.m | 10 ++-- createDataDictionary.m | 8 +-- createDatasetDescription.m | 6 +- createFilename.m | 118 ++++++++++++++++++------------------- saveEventsFile.m | 24 ++++---- userInputs.m | 22 +++---- 8 files changed, 109 insertions(+), 111 deletions(-) diff --git a/checkCFG.m b/checkCFG.m index 2dd50246..2219ab47 100644 --- a/checkCFG.m +++ b/checkCFG.m @@ -1,4 +1,4 @@ -function [cfg, expParameters] = checkCFG(cfg, expParameters) +function cfg = checkCFG(cfg) % check that we have all the fields that we need in the experiment parameters checkCppBidsDependencies(); @@ -6,9 +6,7 @@ if nargin < 1 || isempty(cfg) cfg = struct(); end - if nargin < 2 || isempty(expParameters) - expParameters = struct(); - end + %% set the expParameters defaults @@ -24,35 +22,35 @@ fieldsToSet.sessionNb = 1; % in case no session was provided fieldsToSet.askGrpSess = [true true]; - expParameters = setDefaultFields(expParameters, fieldsToSet); + cfg = setDefaultFields(cfg, fieldsToSet); %% BIDS clear fieldsToSet; fieldsToSet.bids = struct(); - expParameters = setDefaultFields(expParameters, fieldsToSet); + cfg = setDefaultFields(cfg, fieldsToSet); clear fieldsToSet; fieldsToSet.MRI = struct(); fieldsToSet.datasetDescription = struct(); - expParameters.bids = setDefaultFields(expParameters.bids, fieldsToSet); + cfg.bids = setDefaultFields(cfg.bids, fieldsToSet); clear fieldsToSet; fieldsToSet = datasetDescriptionDefaults(); - expParameters.bids.datasetDescription = ... - setDefaultFields(expParameters.bids.datasetDescription, fieldsToSet); + cfg.bids.datasetDescription = ... + setDefaultFields(cfg.bids.datasetDescription, fieldsToSet); clear fieldsToSet; fieldsToSet = mriJsonDefaults(); - if isfield(expParameters, 'task') - fieldsToSet.TaskName = expParameters.task; + if isfield(cfg, 'task') + fieldsToSet.TaskName = cfg.task; end - expParameters.bids.MRI = ... - setDefaultFields(expParameters.bids.MRI, fieldsToSet); + cfg.bids.MRI = ... + setDefaultFields(cfg.bids.MRI, fieldsToSet); % sort fields alphabetically - expParameters = orderfields(expParameters); + cfg = orderfields(cfg); %% set the cfg defaults diff --git a/convertSourceToRaw.m b/convertSourceToRaw.m index 10747eef..4ecd5c81 100644 --- a/convertSourceToRaw.m +++ b/convertSourceToRaw.m @@ -1,7 +1,7 @@ -function convertSourceToRaw(expParameters) +function convertSourceToRaw(cfg) - sourceDir = fullfile(expParameters.outputDir, 'source'); - rawDir = fullfile(expParameters.outputDir, 'rawdata'); + sourceDir = fullfile(cfg.outputDir, 'source'); + rawDir = fullfile(cfg.outputDir, 'rawdata'); % add dummy readme and change file copyfile(fullfile('..', 'dummyData', 'README'), sourceDir); diff --git a/createBoldJson.m b/createBoldJson.m index fcb14059..4d3b7b8f 100644 --- a/createBoldJson.m +++ b/createBoldJson.m @@ -1,16 +1,16 @@ -function createBoldJson(expParameters) +function createBoldJson(cfg) opts.Indent = ' '; - fileName = strrep(expParameters.fileName.events, '_events', '_bold'); + fileName = strrep(cfg.fileName.events, '_events', '_bold'); fileName = strrep(fileName, '.tsv', '.json'); fileName = fullfile( ... - expParameters.subjectOutputDir, ... - expParameters.modality, ... + cfg.subjectOutputDir, ... + cfg.modality, ... fileName); - jsonContent = expParameters.bids.MRI; + jsonContent = cfg.bids.MRI; bids.util.jsonencode(fileName, jsonContent, opts); diff --git a/createDataDictionary.m b/createDataDictionary.m index 828e3918..c4d59fe3 100644 --- a/createDataDictionary.m +++ b/createDataDictionary.m @@ -1,12 +1,12 @@ -function createDataDictionary(expParameters, logFile) +function createDataDictionary(cfg, logFile) opts.Indent = ' '; - fileName = strrep(expParameters.fileName.events, '.tsv', '.json'); + fileName = strrep(cfg.fileName.events, '.tsv', '.json'); fileName = fullfile( ... - expParameters.subjectOutputDir, ... - expParameters.modality, ... + cfg.subjectOutputDir, ... + cfg.modality, ... fileName); jsonContent = struct( ... diff --git a/createDatasetDescription.m b/createDatasetDescription.m index 4e1cbb8f..507ca831 100644 --- a/createDatasetDescription.m +++ b/createDatasetDescription.m @@ -1,12 +1,12 @@ -function createDatasetDescription(expParameters) +function createDatasetDescription(cfg) opts.Indent = ' '; fileName = fullfile( ... - expParameters.outputDir, 'source', ... + cfg.outputDir, 'source', ... 'dataset_description.json'); - jsonContent = expParameters.bids.datasetDescription; + jsonContent = cfg.bids.datasetDescription; bids.util.jsonencode(fileName, jsonContent, opts); diff --git a/createFilename.m b/createFilename.m index 40834d4f..61f080af 100644 --- a/createFilename.m +++ b/createFilename.m @@ -1,4 +1,4 @@ -function [cfg, expParameters] = createFilename(cfg, expParameters) +function cfg = createFilename(cfg) % create the BIDS compliant directories and filenames for the behavioral output % for this subject / session / run using the information from cfg and expParameters. % Will also create the right filename for the eyetracking data file. @@ -14,33 +14,33 @@ zeroPadding = 3; pattern = ['%0' num2str(zeroPadding) '.0f']; - expParameters.pattern = pattern; + cfg.pattern = pattern; dateFormat = 'yyyymmddHHMM'; - expParameters.date = datestr(now, dateFormat); + cfg.date = datestr(now, dateFormat); - [cfg, expParameters] = checkCFG(cfg, expParameters); + cfg = checkCFG(cfg); - if ~isfield(expParameters, 'task') - error('createFilename: missing a task name. i.e expParameters.task'); + if ~isfield(cfg, 'task') + error('createFilename: missing a task name. i.e cfg.task'); end - expParameters = getModality(cfg, expParameters); + cfg = getModality(cfg); - expParameters = createDirectories(cfg, expParameters); + cfg = createDirectories(cfg); - expParameters = setSuffixes(expParameters); + cfg = setSuffixes(cfg); - expParameters = setFilenames(cfg, expParameters); + cfg = setFilenames(cfg); - talkToMe(cfg, expParameters); + talkToMe(cfg); cfg = orderfields(cfg); - expParameters = orderfields(expParameters); + cfg = orderfields(cfg); end -function expParameters = getModality(cfg, expParameters) +function cfg = getModality(cfg) switch lower(cfg.testingDevice) case 'pc' @@ -57,17 +57,17 @@ modality = 'beh'; end - expParameters.modality = modality; + cfg.modality = modality; end -function [subjectGrp, subjectNb, sessionNb, modality, taskName] = extractInput(expParameters) +function [subjectGrp, subjectNb, sessionNb, modality, taskName] = extractInput(cfg) - subjectGrp = expParameters.subjectGrp; - subjectNb = expParameters.subjectNb; - sessionNb = expParameters.sessionNb; - modality = expParameters.modality; - taskName = expParameters.task; + subjectGrp = cfg.subjectGrp; + subjectNb = cfg.subjectNb; + sessionNb = cfg.sessionNb; + modality = cfg.modality; + taskName = cfg.task; if isempty(sessionNb) sessionNb = 1; @@ -75,32 +75,32 @@ end -function expParameters = createDirectories(cfg, expParameters) +function cfg = createDirectories(cfg) - [subjectGrp, subjectNb, sessionNb, modality] = extractInput(expParameters); + [subjectGrp, subjectNb, sessionNb, modality] = extractInput(cfg); - pattern = expParameters.pattern; + pattern = cfg.pattern; % output dir - expParameters.subjectOutputDir = fullfile ( ... - expParameters.outputDir, ... + cfg.subjectOutputDir = fullfile ( ... + cfg.outputDir, ... 'source', ... ['sub-' subjectGrp, sprintf(pattern, subjectNb)], ... ['ses-', sprintf(pattern, sessionNb)]); - [~, ~, ~] = mkdir(expParameters.outputDir); - [~, ~, ~] = mkdir(expParameters.subjectOutputDir); - [~, ~, ~] = mkdir(fullfile(expParameters.subjectOutputDir, modality)); + [~, ~, ~] = mkdir(cfg.outputDir); + [~, ~, ~] = mkdir(cfg.subjectOutputDir); + [~, ~, ~] = mkdir(fullfile(cfg.subjectOutputDir, modality)); if cfg.eyeTracker - [~, ~, ~] = mkdir(fullfile(expParameters.subjectOutputDir, 'eyetracker')); + [~, ~, ~] = mkdir(fullfile(cfg.subjectOutputDir, 'eyetracker')); end end -function expParameters = setSuffixes(expParameters) +function cfg = setSuffixes(cfg) - expParameters.runSuffix = ['_run-' sprintf(expParameters.pattern, expParameters.runNb)]; + cfg.runSuffix = ['_run-' sprintf(cfg.pattern, cfg.runNb)]; % set values for the suffixes for the different fields in the BIDS name fields2Check = { ... @@ -112,30 +112,30 @@ }; for iField = 1:numel(fields2Check) - if isempty (expParameters.MRI.(fields2Check{iField})) %#ok<*GFLD> - expParameters.MRI.([fields2Check{iField} 'Suffix']) = ''; %#ok<*SFLD> + if isempty (cfg.MRI.(fields2Check{iField})) %#ok<*GFLD> + cfg.MRI.([fields2Check{iField} 'Suffix']) = ''; %#ok<*SFLD> else - expParameters.MRI.([fields2Check{iField} 'Suffix']) = ... - ['_' fields2Check{iField} '-' getfield(expParameters.MRI, fields2Check{iField})]; + cfg.MRI.([fields2Check{iField} 'Suffix']) = ... + ['_' fields2Check{iField} '-' getfield(cfg.MRI, fields2Check{iField})]; end end end -function expParameters = setFilenames(cfg, expParameters) +function cfg = setFilenames(cfg) - [subjectGrp, subjectNb, sessionNb, modality, taskName] = extractInput(expParameters); + [subjectGrp, subjectNb, sessionNb, modality, taskName] = extractInput(cfg); - runSuffix = expParameters.runSuffix; - pattern = expParameters.pattern; - acqSuffix = expParameters.MRI.acqSuffix ; - ceSuffix = expParameters.MRI.ceSuffix ; - dirSuffix = expParameters.MRI.dirSuffix ; - recSuffix = expParameters.MRI.recSuffix ; - echoSuffix = expParameters.MRI.echoSuffix; + runSuffix = cfg.runSuffix; + pattern = cfg.pattern; + acqSuffix = cfg.MRI.acqSuffix ; + ceSuffix = cfg.MRI.ceSuffix ; + dirSuffix = cfg.MRI.dirSuffix ; + recSuffix = cfg.MRI.recSuffix ; + echoSuffix = cfg.MRI.echoSuffix; - expParameters.datasetDescription.filename = fullfile ( ... - expParameters.outputDir, ... + cfg.datasetDescription.filename = fullfile ( ... + cfg.outputDir, ... 'dataset_description.json'); % create base filename @@ -143,52 +143,52 @@ ['sub-', subjectGrp, sprintf(pattern, subjectNb), ... '_ses-', sprintf(pattern, sessionNb), ... '_task-', taskName]; - expParameters.fileName.base = fileNameBase; + cfg.fileName.base = fileNameBase; switch modality case 'func' - expParameters.fileName.events = ... + cfg.fileName.events = ... [fileNameBase, ... acqSuffix, ceSuffix, ... dirSuffix, recSuffix, ... runSuffix, echoSuffix, ... - '_events_date-' expParameters.date '.tsv']; + '_events_date-' cfg.date '.tsv']; otherwise - expParameters.fileName.events = ... - [fileNameBase, runSuffix, '_events_date-' expParameters.date '.tsv']; + cfg.fileName.events = ... + [fileNameBase, runSuffix, '_events_date-' cfg.date '.tsv']; end - expParameters.fileName.stim = strrep(expParameters.fileName.events, 'events', 'stim'); + cfg.fileName.stim = strrep(cfg.fileName.events, 'events', 'stim'); if cfg.eyeTracker - expParameters.fileName.eyetracker = ... + cfg.fileName.eyetracker = ... [fileNameBase, acqSuffix, ... - runSuffix, '_eyetrack_date-' expParameters.date '.edf']; + runSuffix, '_eyetrack_date-' cfg.date '.edf']; end end -function talkToMe(cfg, expParameters) +function talkToMe(cfg) fprintf(1, '\nData will be saved in this directory:\n\t%s\n', ... - fullfile(expParameters.subjectOutputDir, expParameters.modality)); + fullfile(cfg.subjectOutputDir, cfg.modality)); fprintf(1, '\nData will be saved in this file:\n\t%s\n', ... - expParameters.fileName.events); + cfg.fileName.events); if cfg.eyeTracker fprintf(1, '\nEyetracking data will be saved in this directory:\n\t%s\n', ... - fullfile(expParameters.subjectOutputDir, 'eyetracker')); + fullfile(cfg.subjectOutputDir, 'eyetracker')); fprintf(1, '\nEyetracking data will be saved in this file:\n\t%s\n', ... - expParameters.fileName.eyetracker); + cfg.fileName.eyetracker); end diff --git a/saveEventsFile.m b/saveEventsFile.m index 9945bdf6..deb30ece 100644 --- a/saveEventsFile.m +++ b/saveEventsFile.m @@ -1,4 +1,4 @@ -function [logFile] = saveEventsFile(action, expParameters, logFile) +function [logFile] = saveEventsFile(action, cfg, logFile) % Function to save output files for events that will be BIDS compliant. % % INPUTS @@ -47,7 +47,7 @@ end if nargin < 2 - expParameters = struct(); + cfg = struct(); end if nargin < 3 || isempty(logFile) @@ -62,15 +62,15 @@ case 'open' - logFile.filename = expParameters.fileName.events; + logFile.filename = cfg.fileName.events; - logFile = initializeFile(expParameters, logFile); + logFile = initializeFile(cfg, logFile); case 'open_stim' - logFile.filename = expParameters.fileName.stim; + logFile.filename = cfg.fileName.stim; - logFile = initializeFile(expParameters, logFile); + logFile = initializeFile(cfg, logFile); case 'save' @@ -116,8 +116,8 @@ fprintf(1, '\nData were saved in this file:\n\n%s\n\n', ... fullfile( ... - expParameters.subjectOutputDir, ... - expParameters.modality, ... + cfg.subjectOutputDir, ... + cfg.modality, ... logFile.filename)); otherwise @@ -169,18 +169,18 @@ end -function logFile = initializeFile(expParameters, logFile) +function logFile = initializeFile(cfg, logFile) logFile = initializeExtraColumns(logFile); - createDataDictionary(expParameters, logFile); + createDataDictionary(cfg, logFile); % Initialize txt logfiles and empty fields for the standard BIDS % event file logFile.fileID = fopen( ... fullfile( ... - expParameters.subjectOutputDir, ... - expParameters.modality, ... + cfg.subjectOutputDir, ... + cfg.modality, ... logFile.filename), ... 'w'); diff --git a/userInputs.m b/userInputs.m index a6433949..d7c055d9 100644 --- a/userInputs.m +++ b/userInputs.m @@ -1,4 +1,4 @@ -function [expParameters] = userInputs(cfg, expParameters) +function cfg = userInputs(cfg) % Get subject, run and session number and make sure they are % positive integer values % @@ -8,16 +8,16 @@ % group % - the second value set to false will skip asking for the session - if nargin < 1 || isempty(cfg.debug) - cfg.debug = false; + if nargin < 1 + cfg = []; end - if nargin < 2 - expParameters = []; + if isempty(cfg.debug) + cfg.debug = false; end askGrpSess = [true true]; - if isfield(expParameters, 'askGrpSess') && ~isempty(expParameters.askGrpSess) - askGrpSess = expParameters.askGrpSess; + if isfield(cfg, 'askGrpSess') && ~isempty(cfg.askGrpSess) + askGrpSess = cfg.askGrpSess; end if numel(askGrpSess) < 2 askGrpSess(2) = 1; @@ -59,10 +59,10 @@ end - expParameters.subjectGrp = subjectGrp; - expParameters.subjectNb = subjectNb; - expParameters.sessionNb = sessionNb; - expParameters.runNb = runNb; + cfg.subjectGrp = subjectGrp; + cfg.subjectNb = subjectNb; + cfg.sessionNb = sessionNb; + cfg.runNb = runNb; end From e8a469ee9d9337ef0169a486b270a0025e07e235 Mon Sep 17 00:00:00 2001 From: Ceren Date: Mon, 27 Jul 2020 22:56:52 +0100 Subject: [PATCH 03/22] tests without expParam --- tests/test_checkCFG.m | 34 +++++++------ tests/test_createBoldJson.m | 18 +++---- tests/test_createDataDictionary.m | 17 +++---- tests/test_createDatasetDescription.m | 15 +++--- tests/test_createFilename.m | 58 +++++++++++----------- tests/test_saveEventsFileInit.m | 8 +-- tests/test_saveEventsFileOpen.m | 36 +++++++------- tests/test_saveEventsFileOpenMultiColumn.m | 20 ++++---- tests/test_saveEventsFileSave.m | 24 ++++----- tests/testmanual_makeRawDataset.m | 32 ++++++------ tests/userInput_test.m | 39 +++++++-------- 11 files changed, 150 insertions(+), 151 deletions(-) diff --git a/tests/test_checkCFG.m b/tests/test_checkCFG.m index 2db865f2..d6e9a080 100644 --- a/tests/test_checkCFG.m +++ b/tests/test_checkCFG.m @@ -1,12 +1,13 @@ function test_checkCFG() - expParameters.outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); - [cfg, expParameters] = checkCFG([], expParameters); + cfg.outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); + cfg = checkCFG(cfg); expectedStructure = returnExpectedStructure(); - expectedStructure.outputDir = expParameters.outputDir; + expectedStructure.outputDir = cfg.outputDir; + expectedStructure.testingDevice = 'pc'; - assert(isequal(expectedStructure, expParameters)); + assert(isequal(expectedStructure, cfg)); %% fprintf('\n--------------------------------------------------------------------'); @@ -15,20 +16,20 @@ function test_checkCFG() outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); - expParameters.subjectNb = 1; - expParameters.runNb = 1; - expParameters.task = 'testtask'; - expParameters.outputDir = outputDir; + cfg.subjectNb = 1; + cfg.runNb = 1; + cfg.task = 'testtask'; + cfg.outputDir = outputDir; - expParameters.bids.datasetDescription.Name = 'dummy'; - expParameters.bids.datasetDescription.BIDSVersion = '1.0.0'; - expParameters.bids.datasetDescription.Authors = {'Jane Doe', 'John Doe'}; + cfg.bids.datasetDescription.Name = 'dummy'; + cfg.bids.datasetDescription.BIDSVersion = '1.0.0'; + cfg.bids.datasetDescription.Authors = {'Jane Doe', 'John Doe'}; - expParameters.bids.MRI.RepetitionTime = 1.56; + cfg.bids.MRI.RepetitionTime = 1.56; cfg.testingDevice = 'mri'; - [~, expParameters] = checkCFG(cfg, expParameters); + cfg = checkCFG(cfg); %%% test @@ -40,6 +41,7 @@ function test_checkCFG() expectedStructure.outputDir = outputDir; expectedStructure.task = 'testtask'; + expectedStructure.testingDevice = 'mri' expectedStructure.bids.MRI.RepetitionTime = 1.56; expectedStructure.bids.MRI.TaskName = 'testtask'; @@ -50,7 +52,7 @@ function test_checkCFG() expectedStructure = orderfields(expectedStructure); - assert(isequal(expectedStructure, expParameters)); + assert(isequal(expectedStructure, cfg)); fprintf('\n'); @@ -63,7 +65,9 @@ function test_checkCFG() expectedStructure.verbose = 0; expectedStructure.askGrpSess = [true true]; - + + expectedStructure.eyeTracker = false; + expectedStructure.MRI.ce = []; expectedStructure.MRI.dir = []; expectedStructure.MRI.rec = []; diff --git a/tests/test_createBoldJson.m b/tests/test_createBoldJson.m index b5bd9130..6d461384 100644 --- a/tests/test_createBoldJson.m +++ b/tests/test_createBoldJson.m @@ -4,26 +4,26 @@ function test_createBoldJson() %%% set up part - expParameters.subjectNb = 1; - expParameters.runNb = 1; - expParameters.task = 'testtask'; - expParameters.outputDir = outputDir; + cfg.subjectNb = 1; + cfg.runNb = 1; + cfg.task = 'testtask'; + cfg.outputDir = outputDir; - cfg = struct(); + %cfg = struct(); cfg.testingDevice = 'mri'; - [cfg, expParameters] = createFilename(cfg, expParameters); %#ok<*ASGLU> + cfg = createFilename(cfg); - logFile = saveEventsFile('init', expParameters); %#ok<*NASGU> + logFile = saveEventsFile('init', cfg); %#ok<*NASGU> - createBoldJson(expParameters); + createBoldJson(cfg); %%% test part % test data funcDir = fullfile(outputDir, 'source', 'sub-001', 'ses-001', 'func'); eventFilename = ['sub-001_ses-001_task-testtask_run-001_bold_date-' ... - expParameters.date '.json']; + cfg.date '.json']; % check that the file has the right path and name assert(exist(fullfile(funcDir, eventFilename), 'file') == 2); diff --git a/tests/test_createDataDictionary.m b/tests/test_createDataDictionary.m index d5875706..53e14ee5 100644 --- a/tests/test_createDataDictionary.m +++ b/tests/test_createDataDictionary.m @@ -6,28 +6,27 @@ function test_createDataDictionary() %%% set up part - expParameters.subjectNb = 1; - expParameters.runNb = 1; - expParameters.task = 'testtask'; - expParameters.outputDir = outputDir; + cfg.subjectNb = 1; + cfg.runNb = 1; + cfg.task = 'testtask'; + cfg.outputDir = outputDir; - cfg = struct(); cfg.testingDevice = 'mri'; - [cfg, expParameters] = createFilename(cfg, expParameters); %#ok + cfg = createFilename(cfg); logFile.extraColumns.Speed.length = 1; logFile.extraColumns.LHL24.length = 3; - logFile = saveEventsFile('init', expParameters, logFile); + logFile = saveEventsFile('init', cfg, logFile); - createDataDictionary(expParameters, logFile); + createDataDictionary(cfg, logFile); %%% test part % test data funcDir = fullfile(outputDir, 'source', 'sub-001', 'ses-001', 'func'); jsonFilename = ['sub-001_ses-001_task-testtask_run-001_events_date-' ... - expParameters.date '.json']; + cfg.date '.json']; % check that the file has the right path and name assert(exist(fullfile(funcDir, jsonFilename), 'file') == 2); diff --git a/tests/test_createDatasetDescription.m b/tests/test_createDatasetDescription.m index 07ee42f5..90a38335 100644 --- a/tests/test_createDatasetDescription.m +++ b/tests/test_createDatasetDescription.m @@ -4,18 +4,17 @@ function test_createDatasetDescription() %%% set up part - expParameters.outputDir = outputDir; + cfg.outputDir = outputDir; - expParameters.bids.datasetDescription.json.Name = 'dummy_dataset'; - expParameters.bids.datasetDescription.json.BIDSVersion = '1.0.0'; - expParameters.bids.datasetDescription.json.License = 'none'; - expParameters.bids.datasetDescription.json.Authors = {'Jane Doe'}; + cfg.bids.datasetDescription.json.Name = 'dummy_dataset'; + cfg.bids.datasetDescription.json.BIDSVersion = '1.0.0'; + cfg.bids.datasetDescription.json.License = 'none'; + cfg.bids.datasetDescription.json.Authors = {'Jane Doe'}; - cfg = struct(); - [cfg, expParameters] = checkCFG(cfg, expParameters); %#ok<*ASGLU> + cfg = checkCFG(cfg); - createDatasetDescription(expParameters); + createDatasetDescription(cfg); %%% test part diff --git a/tests/test_createFilename.m b/tests/test_createFilename.m index 171ed583..620367a4 100644 --- a/tests/test_createFilename.m +++ b/tests/test_createFilename.m @@ -7,15 +7,13 @@ function test_createFilename() %%% set up part - expParameters.subjectNb = 1; - expParameters.runNb = 1; - expParameters.task = 'testtask'; - expParameters.outputDir = outputDir; - - cfg = struct(); + cfg.subjectNb = 1; + cfg.runNb = 1; + cfg.task = 'testtask'; + cfg.outputDir = outputDir; %%% run part - [cfg, expParameters] = createFilename(cfg, expParameters); + cfg = createFilename(cfg); %%% test part @@ -23,9 +21,9 @@ function test_createFilename() behDir = fullfile(outputDir, 'source', 'sub-001', 'ses-001', 'beh'); eyetrackerDir = fullfile(outputDir, 'source', 'sub-001', 'ses-001', 'eyetracker'); eventFilename = ['sub-001_ses-001_task-testtask_run-001_events_date-'... - expParameters.date '.tsv']; + cfg.date '.tsv']; stimFilename = ['sub-001_ses-001_task-testtask_run-001_stim_date-'... - expParameters.date '.tsv']; + cfg.date '.tsv']; % make sure the beh dir is created assert(exist(behDir, 'dir') == 7); @@ -34,10 +32,10 @@ function test_createFilename() assert(exist(eyetrackerDir, 'dir') == 0); % make sure the events filename is created - assert(strcmp(expParameters.fileName.events, eventFilename)); + assert(strcmp(cfg.fileName.events, eventFilename)); % make sure the stim filename is created - assert(strcmp(expParameters.fileName.stim, stimFilename)); + assert(strcmp(cfg.fileName.stim, stimFilename)); %% fMRI and eye tracker fprintf('\n--------------------------------------------------------------------'); @@ -48,17 +46,17 @@ function test_createFilename() %%% set up part - expParameters.subjectGrp = 'ctrl'; - expParameters.subjectNb = 2; - expParameters.sessionNb = 2; - expParameters.runNb = 2; - expParameters.task = 'testtask'; - expParameters.outputDir = outputDir; + cfg.subjectGrp = 'ctrl'; + cfg.subjectNb = 2; + cfg.sessionNb = 2; + cfg.runNb = 2; + cfg.task = 'testtask'; + cfg.outputDir = outputDir; cfg.eyeTracker = true; cfg.testingDevice = 'mri'; - [cfg, expParameters] = createFilename(cfg, expParameters); + cfg = createFilename(cfg); %%% test part @@ -67,9 +65,9 @@ function test_createFilename() eyetrackerDir = fullfile(outputDir, 'source', 'sub-ctrl002', 'ses-002', 'eyetracker'); baseFilename = 'sub-ctrl002_ses-002_task-testtask'; eventFilename = ['sub-ctrl002_ses-002_task-testtask_run-002_events_date-' ... - expParameters.date '.tsv']; + cfg.date '.tsv']; eyetrackerFilename = ['sub-ctrl002_ses-002_task-testtask_run-002_eyetrack_date-' ... - expParameters.date '.edf']; + cfg.date '.edf']; % make sure the func dir is created assert(exist(funcDir, 'dir') == 7); @@ -78,9 +76,9 @@ function test_createFilename() assert(exist(eyetrackerDir, 'dir') == 7); % make sure the right filenames are created - assert(strcmp(expParameters.fileName.base, baseFilename)); - assert(strcmp(expParameters.fileName.events, eventFilename)); - assert(strcmp(expParameters.fileName.eyetracker, eyetrackerFilename)); + assert(strcmp(cfg.fileName.base, baseFilename)); + assert(strcmp(cfg.fileName.events, eventFilename)); + assert(strcmp(cfg.fileName.eyetracker, eyetrackerFilename)); %% EEG fprintf('\n--------------------------------------------------------------------'); @@ -91,16 +89,16 @@ function test_createFilename() %%% set up part - expParameters.subjectGrp = 'blind'; - expParameters.subjectNb = 3; - expParameters.sessionNb = 1; - expParameters.runNb = 1; - expParameters.task = 'testtask'; - expParameters.outputDir = outputDir; + cfg.subjectGrp = 'blind'; + cfg.subjectNb = 3; + cfg.sessionNb = 1; + cfg.runNb = 1; + cfg.task = 'testtask'; + cfg.outputDir = outputDir; cfg.testingDevice = 'eeg'; - [cfg, expParameters] = createFilename(cfg, expParameters); %#ok + cfg = createFilename(cfg); %%% test part diff --git a/tests/test_saveEventsFileInit.m b/tests/test_saveEventsFileInit.m index 765f96f3..bf0a1daa 100644 --- a/tests/test_saveEventsFileInit.m +++ b/tests/test_saveEventsFileInit.m @@ -21,11 +21,11 @@ function test_saveEventsFileInit() clear; %%% set up - [cfg, expParameters] = checkCFG(); %#ok + cfg = checkCFG(); logFile.extraColumns = {'Speed'}; %%% do stuff - [logFile] = saveEventsFile('init', expParameters, logFile); + [logFile] = saveEventsFile('init', cfg, logFile); %%% test section expectedStrcut(1).extraColumns.Speed.length = 1; @@ -42,12 +42,12 @@ function test_saveEventsFileInit() clear; %%% set up - [cfg, expParameters] = checkCFG(); %#ok + cfg = checkCFG(); logFile.extraColumns.Speed.length = 1; logFile.extraColumns.LHL24.length = 3; %%% do stuff - [logFile] = saveEventsFile('init', expParameters, logFile); + [logFile] = saveEventsFile('init', cfg, logFile); %%% test section expectedStrcut(1).extraColumns.Speed.length = 1; diff --git a/tests/test_saveEventsFileOpen.m b/tests/test_saveEventsFileOpen.m index 21d52954..f8b38a07 100644 --- a/tests/test_saveEventsFileOpen.m +++ b/tests/test_saveEventsFileOpen.m @@ -7,29 +7,29 @@ function test_saveEventsFileOpen() %%% set up - expParameters.subjectNb = 1; - expParameters.runNb = 1; - expParameters.task = 'testtask'; - expParameters.outputDir = outputDir; + cfg.subjectNb = 1; + cfg.runNb = 1; + cfg.task = 'testtask'; + cfg.outputDir = outputDir; cfg.testingDevice = 'mri'; %%% do stuff - [cfg, expParameters] = createFilename(cfg, expParameters); + cfg = createFilename(cfg); % create the events file and header - logFile = saveEventsFile('open', expParameters); + logFile = saveEventsFile('open', cfg); % close the file - saveEventsFile('close', expParameters, logFile); + saveEventsFile('close', cfg, logFile); %%% test section % test data funcDir = fullfile(outputDir, 'source', 'sub-001', 'ses-001', 'func'); eventFilename = ['sub-001_ses-001_task-testtask_run-001_events_date-' ... - expParameters.date '.tsv']; + cfg.date '.tsv']; % open the file FID = fopen(fullfile(funcDir, eventFilename), 'r'); @@ -52,10 +52,10 @@ function test_saveEventsFileOpen() %%% set up - expParameters.subjectNb = 1; - expParameters.runNb = 1; - expParameters.task = 'testtask'; - expParameters.outputDir = outputDir; + cfg.subjectNb = 1; + cfg.runNb = 1; + cfg.task = 'testtask'; + cfg.outputDir = outputDir; cfg.testingDevice = 'mri'; @@ -64,22 +64,22 @@ function test_saveEventsFileOpen() %%% do stuff - [cfg, expParameters] = createFilename(cfg, expParameters); %#ok + cfg = createFilename(cfg); % create the events file and header - logFile = saveEventsFile('open', expParameters, logFile); + logFile = saveEventsFile('open', cfg, logFile); % close the file - saveEventsFile('close', expParameters, logFile); + saveEventsFile('close', cfg, logFile); %%% test section % open the file nbExtraCol = 2; FID = fopen(fullfile( ... - expParameters.subjectOutputDir, ... - expParameters.modality, ... - expParameters.fileName.events), ... + cfg.subjectOutputDir, ... + cfg.modality, ... + cfg.fileName.events), ... 'r'); C = textscan(FID, repmat('%s', 1, nbExtraCol + 3), 'Delimiter', '\t', 'EndOfLine', '\n'); diff --git a/tests/test_saveEventsFileOpenMultiColumn.m b/tests/test_saveEventsFileOpenMultiColumn.m index d1415fbf..c225643b 100644 --- a/tests/test_saveEventsFileOpenMultiColumn.m +++ b/tests/test_saveEventsFileOpenMultiColumn.m @@ -7,14 +7,14 @@ function test_saveEventsFileOpenMultiColumn() %%% set up - expParameters.subjectNb = 1; - expParameters.runNb = 1; - expParameters.task = 'testtask'; - expParameters.outputDir = outputDir; + cfg.subjectNb = 1; + cfg.runNb = 1; + cfg.task = 'testtask'; + cfg.outputDir = outputDir; cfg.testingDevice = 'mri'; - [cfg, expParameters] = createFilename(cfg, expParameters); %#ok + cfg = createFilename(cfg); % define the extra columns: here we specify how many columns we want for % each variable @@ -25,10 +25,10 @@ function test_saveEventsFileOpenMultiColumn() %%% do stuff % create the events file and header - logFile = saveEventsFile('open', expParameters, logFile); + logFile = saveEventsFile('open', cfg, logFile); % close the file - saveEventsFile('close', expParameters, logFile); + saveEventsFile('close', cfg, logFile); %%% test section @@ -38,9 +38,9 @@ function test_saveEventsFileOpenMultiColumn() logFile(1).extraColumns.LHL24.length + ... logFile(1).extraColumns.is_Fixation.length; FID = fopen(fullfile( ... - expParameters.subjectOutputDir, ... - expParameters.modality, ... - expParameters.fileName.events), ... + cfg.subjectOutputDir, ... + cfg.modality, ... + cfg.fileName.events), ... 'r'); C = textscan(FID, repmat('%s', 1, nbExtraCol + 3), 'Delimiter', '\t', 'EndOfLine', '\n'); diff --git a/tests/test_saveEventsFileSave.m b/tests/test_saveEventsFileSave.m index ad3bfe84..40bfaec6 100644 --- a/tests/test_saveEventsFileSave.m +++ b/tests/test_saveEventsFileSave.m @@ -7,21 +7,21 @@ function test_saveEventsFileSave() %%% set up - expParameters.subjectNb = 1; - expParameters.runNb = 1; - expParameters.task = 'testtask'; - expParameters.outputDir = outputDir; + cfg.subjectNb = 1; + cfg.runNb = 1; + cfg.task = 'testtask'; + cfg.outputDir = outputDir; cfg.testingDevice = 'mri'; - [cfg, expParameters] = createFilename(cfg, expParameters); %#ok + cfg = createFilename(cfg); logFile.extraColumns.Speed.length = 1; logFile.extraColumns.LHL24.length = 12; logFile.extraColumns.is_Fixation.length = 1; % create the events file and header - logFile = saveEventsFile('open', expParameters, logFile); + logFile = saveEventsFile('open', cfg, logFile); %%% do stuff @@ -33,7 +33,7 @@ function test_saveEventsFileSave() logFile(end, 1).is_Fixation = true; logFile(end, 1).LHL24 = 1:12; - logFile = saveEventsFile('save', expParameters, logFile); + logFile = saveEventsFile('save', cfg, logFile); % ROW 3: missing info (speed, LHL24) logFile(1, 1).onset = 3; @@ -68,10 +68,10 @@ function test_saveEventsFileSave() % logFile(end, 1).duration = 3; % logFile(end, 1).LHL24 = rand(1, 15); - saveEventsFile('save', expParameters, logFile); + saveEventsFile('save', cfg, logFile); % close the file - saveEventsFile('close', expParameters, logFile); + saveEventsFile('close', cfg, logFile); %%% test section @@ -81,9 +81,9 @@ function test_saveEventsFileSave() logFile(1).extraColumns.LHL24.length + ... logFile(1).extraColumns.is_Fixation.length; FID = fopen(fullfile( ... - expParameters.subjectOutputDir, ... - expParameters.modality, ... - expParameters.fileName.events), ... + cfg.subjectOutputDir, ... + cfg.modality, ... + cfg.fileName.events), ... 'r'); C = textscan(FID, repmat('%s', 1, nbExtraCol + 3), 'Delimiter', '\t', 'EndOfLine', '\n'); diff --git a/tests/testmanual_makeRawDataset.m b/tests/testmanual_makeRawDataset.m index fa0cbe2e..a1929f3a 100644 --- a/tests/testmanual_makeRawDataset.m +++ b/tests/testmanual_makeRawDataset.m @@ -14,16 +14,16 @@ function testmanual_makeRawDataset() %%% set up - expParameters.subjectNb = 1; - expParameters.runNb = 1; - expParameters.task = 'testtask'; - expParameters.outputDir = outputDir; + cfg.subjectNb = 1; + cfg.runNb = 1; + cfg.task = 'testtask'; + cfg.outputDir = outputDir; - expParameters.bids.datasetDescription.Name = 'dummy'; - expParameters.bids.datasetDescription.BIDSVersion = '1.0.0'; - expParameters.bids.datasetDescription.Authors = {'Jane Doe', 'John Doe'}; + cfg.bids.datasetDescription.Name = 'dummy'; + cfg.bids.datasetDescription.BIDSVersion = '1.0.0'; + cfg.bids.datasetDescription.Authors = {'Jane Doe', 'John Doe'}; - expParameters.bids.MRI.RepetitionTime = 1.56; + cfg.bids.MRI.RepetitionTime = 1.56; cfg.testingDevice = 'mri'; @@ -33,13 +33,13 @@ function testmanual_makeRawDataset() %%% do stuff - [cfg, expParameters] = createFilename(cfg, expParameters); %#ok<*ASGLU> + cfg = createFilename(cfg); % create the events file and header - logFile = saveEventsFile('open', expParameters, logFile); + logFile = saveEventsFile('open', cfg, logFile); - createBoldJson(expParameters); - createDatasetDescription(expParameters); + createBoldJson(cfg); + createDatasetDescription(cfg); % ROW 2: normal events : all info is there logFile(1, 1).onset = 2; @@ -68,13 +68,13 @@ function testmanual_makeRawDataset() logFile(end, 1).duration = 3; logFile(end, 1).LHL24 = rand(1, 2); - saveEventsFile('save', expParameters, logFile); + saveEventsFile('save', cfg, logFile); % close the file - saveEventsFile('close', expParameters, logFile); + saveEventsFile('close', cfg, logFile); % add dummy functional data - funcDir = fullfile(expParameters.outputDir, 'source', 'sub-001', 'ses-001', 'func'); + funcDir = fullfile(cfg.outputDir, 'source', 'sub-001', 'ses-001', 'func'); boldFilename = 'sub-001_ses-001_task-testtask_run-001_bold.nii.gz'; copyfile( ... fullfile('..', 'dummyData', 'dummyData.nii.gz'), ... @@ -82,5 +82,5 @@ function testmanual_makeRawDataset() %% - convertSourceToRaw(expParameters); + convertSourceToRaw(cfg); end diff --git a/tests/userInput_test.m b/tests/userInput_test.m index eae757a7..b8fa2846 100644 --- a/tests/userInput_test.m +++ b/tests/userInput_test.m @@ -1,34 +1,33 @@ %% -cfg = struct('debug', true); -expParameters = struct(); +cfg.debug = true; -[expParameters] = userInputs(cfg, expParameters); -disp(expParameters); +cfg = userInputs(cfg); +disp(cfg); %% -cfg = struct('debug', false); -expParameters = struct('askGrpSess', 0); +cfg.debug = false; +cfg.askGrpSess = 0; -[expParameters] = userInputs(cfg, expParameters); -disp(expParameters); +cfg = userInputs(cfg); +disp(cfg); %% -cfg = struct('debug', false); -expParameters = struct('askGrpSess', [0 0]); +cfg.debug = false; +cfg.askGrpSess = [0 0]; -[expParameters] = userInputs(cfg, expParameters); -disp(expParameters); +cfg = userInputs(cfg); +disp(cfg); %% -cfg = struct('debug', false); -expParameters = struct('askGrpSess', [0 1]); +cfg.debug = false; +cfg.askGrpSess = [0 1]; -[expParameters] = userInputs(cfg, expParameters); -disp(expParameters); +cfg = userInputs(cfg); +disp(cfg); %% -cfg = struct('debug', false); -expParameters = struct('askGrpSess', []); +cfg.debug = false; +cfg.askGrpSess = []; -[expParameters] = userInputs(cfg, expParameters); -disp(expParameters); +cfg = userInputs(cfg); +disp(cfg); From f358d2d71c2f5d45f14384fe9a43bd9c516b10d8 Mon Sep 17 00:00:00 2001 From: Ceren Date: Mon, 27 Jul 2020 23:01:29 +0100 Subject: [PATCH 04/22] semicolon add --- checkCppBidsDependencies.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/checkCppBidsDependencies.m b/checkCppBidsDependencies.m index 97edb06e..5daff764 100644 --- a/checkCppBidsDependencies.m +++ b/checkCppBidsDependencies.m @@ -2,8 +2,8 @@ pth = fileparts(mfilename('fullpath')); - checkSubmodule(fullfile(pth, 'lib', 'JSONio')) - checkSubmodule(fullfile(pth, 'lib', 'bids-matlab')) + checkSubmodule(fullfile(pth, 'lib', 'JSONio')); + checkSubmodule(fullfile(pth, 'lib', 'bids-matlab')); addpath(fullfile(pth, 'lib', 'utils')); addpath(fullfile(pth, 'subfun')); From 0aa7060f29b815c1ab43f9e84e3c6bf35c9fb4a1 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 28 Jul 2020 17:58:36 +0200 Subject: [PATCH 05/22] make setDefaultFields recursive and test for it --- subfun/setDefaultFields.m | 13 ++++++++++++- tests/test_setDefaultFields.m | 30 ++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 tests/test_setDefaultFields.m diff --git a/subfun/setDefaultFields.m b/subfun/setDefaultFields.m index 75669017..ad5f2644 100644 --- a/subfun/setDefaultFields.m +++ b/subfun/setDefaultFields.m @@ -1,16 +1,27 @@ function structure = setDefaultFields(structure, fieldsToSet) - % loop through the defaults fiels to set and update if they don't exist + % structure = setDefaultFields(structure, fieldsToSet) + % + % recursively loop through the fields of a structure and sets a value if they don't exist + % names = fieldnames(fieldsToSet); for i = 1:numel(names) thisField = fieldsToSet.(names{i}); + + if isfield(structure, names{i}) && isstruct(structure.(names{i})) + + structure.(names{i}) = ... + setDefaultFields(structure.(names{i}), fieldsToSet.(names{i})); + + else structure = setFieldToIfNotPresent( ... structure, ... names{i}, ... thisField); + end end diff --git a/tests/test_setDefaultFields.m b/tests/test_setDefaultFields.m new file mode 100644 index 00000000..9897938f --- /dev/null +++ b/tests/test_setDefaultFields.m @@ -0,0 +1,30 @@ +function test_setDefaultFields() + + structure = struct(); + + fieldsToSet.field = 1; + + structure = setDefaultFields(structure, fieldsToSet); + + expectedStructure.field = 1; + + assert(isequal(expectedStructure, structure)); + + fprintf('\n--------------------------------------------------------------------'); + + clear + + structure.field.subfield_1 = 3; + + fieldsToSet.field.subfield_1 = 1; + fieldsToSet.field.subfield_2 = 1; + + structure = setDefaultFields(structure, fieldsToSet); + + expectedStructure.field.subfield_1 = 3; + expectedStructure.field.subfield_2 = 1; + + assert(isequal(expectedStructure, structure)); + +end + From 4713b2e25305657fed7df479394c894845aaf1ec Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 28 Jul 2020 18:50:23 +0200 Subject: [PATCH 06/22] add sub-structures to checkCFG - add BIDS MEG info - adds comment - update and refactor test --- checkCFG.m | 243 +++++++++++++++++++++++++++--------------- tests/test_checkCFG.m | 160 +++++++++++++++++---------- 2 files changed, 261 insertions(+), 142 deletions(-) diff --git a/checkCFG.m b/checkCFG.m index 2219ab47..db9d6d6d 100644 --- a/checkCFG.m +++ b/checkCFG.m @@ -1,108 +1,185 @@ function cfg = checkCFG(cfg) % check that we have all the fields that we need in the experiment parameters - + % reuses a lot of code from the BIDS starter kit + checkCppBidsDependencies(); - + if nargin < 1 || isempty(cfg) cfg = struct(); end - - - %% set the expParameters defaults - + + %% set the cfg defaults + fieldsToSet.verbose = false; - fieldsToSet.outputDir = fullfile( ... + + fieldsToSet.dir.output = fullfile( ... fileparts(mfilename('fullpath')), ... '..', ... 'output'); - + + fieldsToSet.subject.askGrpSess = [true true]; + fieldsToSet.subject.sessionNb = 1; % in case no session was provided + fieldsToSet.subject.subjectGrp = ''; % in case no group was provided + + fieldsToSet.testingDevice = 'pc'; + + fieldsToSet.eyeTracker = struct(); + + fieldsToSet.eyeTracker.do = false; + fieldsToSet = mriDefaults(fieldsToSet); - - fieldsToSet.subjectGrp = ''; % in case no group was provided - fieldsToSet.sessionNb = 1; % in case no session was provided - fieldsToSet.askGrpSess = [true true]; - - cfg = setDefaultFields(cfg, fieldsToSet); - + %% BIDS - clear fieldsToSet; - fieldsToSet.bids = struct(); - cfg = setDefaultFields(cfg, fieldsToSet); - - clear fieldsToSet; - fieldsToSet.MRI = struct(); - fieldsToSet.datasetDescription = struct(); - cfg.bids = setDefaultFields(cfg.bids, fieldsToSet); - - clear fieldsToSet; - fieldsToSet = datasetDescriptionDefaults(); - - cfg.bids.datasetDescription = ... - setDefaultFields(cfg.bids.datasetDescription, fieldsToSet); - - clear fieldsToSet; - fieldsToSet = mriJsonDefaults(); - if isfield(cfg, 'task') - fieldsToSet.TaskName = cfg.task; + + fieldsToSet = datasetDescriptionDefaults(fieldsToSet); + + fieldsToSet = mriJsonDefaults(fieldsToSet); + if isfield(cfg, 'task') && isfield(cfg.task, 'name') + fieldsToSet.bids.mri.TaskName = cfg.task.name; end - - cfg.bids.MRI = ... - setDefaultFields(cfg.bids.MRI, fieldsToSet); - - % sort fields alphabetically - cfg = orderfields(cfg); - - %% set the cfg defaults - - clear fieldsToSet; - fieldsToSet.verbose = false; - fieldsToSet.testingDevice = 'pc'; - fieldsToSet.eyeTracker = false; - + + fieldsToSet = megJsonDefaults(fieldsToSet); + if isfield(cfg, 'task') && isfield(cfg.task, 'name') + fieldsToSet.bids.meg.TaskName = cfg.task.name; + end + cfg = setDefaultFields(cfg, fieldsToSet); - - % sort fields alphabetically - cfg = orderfields(cfg); - + end function fieldsToSet = mriDefaults(fieldsToSet) - + % for file naming - fieldsToSet.MRI.ce = []; - fieldsToSet.MRI.dir = []; % phase encoding direction of acquisition for fMRI - fieldsToSet.MRI.rec = []; % reconstruction of fMRI images - fieldsToSet.MRI.echo = []; % echo fMRI images - fieldsToSet.MRI.acq = []; % acquisition of fMRI images + fieldsToSet.fileName.mri.ce = []; + fieldsToSet.fileName.mri.dir = []; % phase encoding direction of acquisition for fMRI + fieldsToSet.fileName.mri.rec = []; % reconstruction of fMRI images + fieldsToSet.fileName.mri.echo = []; % echo fMRI images + fieldsToSet.fileName.mri.acq = []; % acquisition of fMRI images + +end +function fieldsToSet = datasetDescriptionDefaults(fieldsToSet) + + % REQUIRED name of the dataset + fieldsToSet.bids.datasetDescription.Name = ''; + + % REQUIRED The version of the BIDS standard that was used + fieldsToSet.bids.datasetDescription.BIDSVersion = ''; + + % RECOMMENDED + % what license is this dataset distributed under? The + % use of license name abbreviations is suggested for specifying a license. + % A list of common licenses with suggested abbreviations can be found in appendix III. + fieldsToSet.bids.datasetDescription.License = ''; + + % RECOMMENDED List of individuals who contributed to the + % creation/curation of the dataset + fieldsToSet.bids.datasetDescription.Authors = {''}; + + % RECOMMENDED who should be acknowledge in helping to collect the data + fieldsToSet.bids.datasetDescription.Acknowledgements = ''; + + % RECOMMENDED Instructions how researchers using this + % dataset should acknowledge the original authors. This field can also be used + % to define a publication that should be cited in publications that use the + % dataset. + fieldsToSet.bids.datasetDescription.HowToAcknowledge = ''; + + % RECOMMENDED sources of funding (grant numbers) + fieldsToSet.bids.datasetDescription.Funding = {''}; + + % RECOMMENDED a list of references to + % publication that contain information on the dataset, or links. + fieldsToSet.bids.datasetDescription.ReferencesAndLinks = {''}; + + % RECOMMENDED the Document Object Identifier of the dataset + % (not the corresponding paper). + fieldsToSet.bids.datasetDescription.DatasetDOI = ''; + + % sort fields alphabetically + fieldsToSet = orderfields(fieldsToSet); + end -function fieldsToSet = datasetDescriptionDefaults() - % required - fieldsToSet.Name = ''; - fieldsToSet.BIDSVersion = ''; - % recommended - fieldsToSet.License = ''; - fieldsToSet.Authors = {''}; - fieldsToSet.Acknowledgements = ''; - fieldsToSet.HowToAcknowledge = ''; - fieldsToSet.Funding = {''}; - fieldsToSet.ReferencesAndLinks = {''}; - fieldsToSet.DatasetDOI = ''; +function fieldsToSet = mriJsonDefaults(fieldsToSet) + % for json for funcfional MRI data + + % REQUIRED The time in seconds between the beginning of an acquisition of + % one volume and the beginning of acquisition of the volume following it + % (TR). Please note that this definition includes time between scans + % (when no data has been acquired) in case of sparse acquisition schemes. + % This value needs to be consistent with the pixdim[4] field + % (after accounting for units stored in xyzt_units field) in the NIfTI header + fieldsToSet.bids.mri.RepetitionTime = []; + + % REQUIRED for sparse sequences that do not have the DelayTime field set. + % This parameter is required for sparse sequences. In addition without this + % parameter slice time correction will not be possible. + % + % In addition without this parameter slice time correction will not be possible. + % The time at which each slice was acquired within each volume (frame) of the acquisition. + % The time at which each slice was acquired during the acquisition. Slice + % timing is not slice order - it describes the time (sec) of each slice + % acquisition in relation to the beginning of volume acquisition. It is + % described using a list of times (in JSON format) referring to the acquisition + % time for each slice. The list goes through slices along the slice axis in the + % slice encoding dimension. + fieldsToSet.bids.mri.SliceTiming = []; + + % REQUIRED Name of the task (for resting state use the "rest" prefix). No two tasks + % should have the same name. Task label is derived from this field by + % removing all non alphanumeric ([a-zA-Z0-9]) characters. + fieldsToSet.bids.mri.TaskName = []; + + % RECOMMENDED Text of the instructions given to participants before the scan. + % This is especially important in context of resting state fMRI and + % distinguishing between eyes open and eyes closed paradigms. + fieldsToSet.bids.mri.Instructions = ''; + + % RECOMMENDED Longer description of the task. + fieldsToSet.bids.mri.TaskDescription = ''; + + % fieldsToSet.PhaseEncodingDirection = []; + % fieldsToSet.EffectiveEchoSpacing = []; + % fieldsToSet.EchoTime = []; + end -function fieldsToSet = mriJsonDefaults() +function fieldsToSet = megJsonDefaults(fieldsToSet) + % for json for MEG data + + % REQUIRED Name of the task (for resting state use the "rest" prefix). No two tasks + % should have the same name. Task label is derived from this field by + % removing all non alphanumeric ([a-zA-Z0-9]) characters. + fieldsToSet.bids.meg.TaskName = []; + + % REQUIRED Sampling frequency + fieldsToSet.bids.meg.SamplingFrequency = []; + + % REQUIRED Frequency (in Hz) of the power grid at the geographical location of + % the MEG instrument (i.e. 50 or 60): + fieldsToSet.bids.meg.PowerLineFrequency = []; + + % REQUIRED Position of the dewar during the MEG scan: "upright", "supine" or + % "degrees" of angle from vertical: for example on CTF systems, + % upright=15°, supine = 90°: + fieldsToSet.bids.meg.DewarPosition = []; + + % REQUIRED List of temporal and/or spatial software filters applied, or ideally + % key:value pairs of pre-applied software filters and their parameter + % values: e.g., {"SSS": {"frame": "head", "badlimit": 7}}, + % {"SpatialCompensation": {"GradientOrder": Order of the gradient + % compensation}}. Write “n/a” if no software filters applied. + fieldsToSet.bids.meg.SoftwareFilters = []; + + % REQUIRED Boolean (“true” or “false”) value indicating whether anatomical + % landmark points (i.e. fiducials) are contained within this recording. + fieldsToSet.bids.meg.DigitizedLandmarks = []; + + % REQUIRED Boolean (“true” or “false”) value indicating whether head points + % outlining the scalp/face surface are contained within this recording + fieldsToSet.bids.meg.DigitizedHeadPoints = []; + +end - % for json for funcfional data - % required - fieldsToSet.RepetitionTime = []; - fieldsToSet.SliceTiming = []; - fieldsToSet.TaskName = []; - % fieldsToSet.PhaseEncodingDirection = []; - % fieldsToSet.EffectiveEchoSpacing = []; - % fieldsToSet.EchoTime = []; - % recommended - fieldsToSet.Instructions = []; - fieldsToSet.TaskDescription = []; -end diff --git a/tests/test_checkCFG.m b/tests/test_checkCFG.m index d6e9a080..c01b92c1 100644 --- a/tests/test_checkCFG.m +++ b/tests/test_checkCFG.m @@ -1,88 +1,97 @@ function test_checkCFG() - - cfg.outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); + + cfg.dir.output = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); cfg = checkCFG(cfg); - + expectedStructure = returnExpectedStructure(); - expectedStructure.outputDir = cfg.outputDir; + expectedStructure.dir.output = cfg.dir.output; expectedStructure.testingDevice = 'pc'; - - assert(isequal(expectedStructure, cfg)); - + + testSubFields(expectedStructure, cfg) + %% fprintf('\n--------------------------------------------------------------------'); - + clear; - + outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); - - cfg.subjectNb = 1; - cfg.runNb = 1; - cfg.task = 'testtask'; - cfg.outputDir = outputDir; - + + cfg.subject.subjectNb = 1; + cfg.subject.runNb = 1; + + cfg.task.name = 'testtask'; + + cfg.dir.output = outputDir; + cfg.bids.datasetDescription.Name = 'dummy'; cfg.bids.datasetDescription.BIDSVersion = '1.0.0'; cfg.bids.datasetDescription.Authors = {'Jane Doe', 'John Doe'}; - - cfg.bids.MRI.RepetitionTime = 1.56; - + + cfg.bids.mri.RepetitionTime = 1.56; + cfg.testingDevice = 'mri'; - + cfg = checkCFG(cfg); - + %%% test - + % test data expectedStructure = returnExpectedStructure(); - expectedStructure.subjectNb = 1; - expectedStructure.runNb = 1; - - expectedStructure.outputDir = outputDir; - - expectedStructure.task = 'testtask'; - expectedStructure.testingDevice = 'mri' - - expectedStructure.bids.MRI.RepetitionTime = 1.56; - expectedStructure.bids.MRI.TaskName = 'testtask'; - + expectedStructure.subject.subjectNb = 1; + expectedStructure.subject.runNb = 1; + + expectedStructure.dir.output = outputDir; + + expectedStructure.task.name = 'testtask'; + expectedStructure.testingDevice = 'mri'; + + expectedStructure.bids.mri.RepetitionTime = 1.56; + expectedStructure.bids.mri.TaskName = 'testtask'; + + expectedStructure.bids.meg.TaskName = 'testtask'; + expectedStructure.bids.datasetDescription.Name = 'dummy'; expectedStructure.bids.datasetDescription.BIDSVersion = '1.0.0'; expectedStructure.bids.datasetDescription.Authors = {'Jane Doe', 'John Doe'}; - + expectedStructure = orderfields(expectedStructure); - - assert(isequal(expectedStructure, cfg)); - + + testSubFields(expectedStructure, cfg) + fprintf('\n'); - + end function expectedStructure = returnExpectedStructure() - - expectedStructure.subjectGrp = ''; - expectedStructure.sessionNb = 1; - + + expectedStructure.subject.subjectGrp = ''; + expectedStructure.subject.sessionNb = 1; + expectedStructure.subject.askGrpSess = [true true]; + expectedStructure.verbose = 0; - expectedStructure.askGrpSess = [true true]; - expectedStructure.eyeTracker = false; + expectedStructure.eyeTracker.do = false; + + expectedStructure.fileName.mri.ce = []; + expectedStructure.fileName.mri.dir = []; + expectedStructure.fileName.mri.rec = []; + expectedStructure.fileName.mri.echo = []; + expectedStructure.fileName.mri.acq = []; + + expectedStructure.bids.mri.RepetitionTime = []; + expectedStructure.bids.mri.SliceTiming = ''; + expectedStructure.bids.mri.TaskName = ''; + expectedStructure.bids.mri.Instructions = ''; + expectedStructure.bids.mri.TaskDescription = ''; + + expectedStructure.bids.meg.TaskName = ''; + expectedStructure.bids.meg.SamplingFrequency = []; + expectedStructure.bids.meg.PowerLineFrequency = []; + expectedStructure.bids.meg.DewarPosition = []; + expectedStructure.bids.meg.SoftwareFilters = []; + expectedStructure.bids.meg.DigitizedLandmarks = []; + expectedStructure.bids.meg.DigitizedHeadPoints = []; - expectedStructure.MRI.ce = []; - expectedStructure.MRI.dir = []; - expectedStructure.MRI.rec = []; - expectedStructure.MRI.echo = []; - expectedStructure.MRI.acq = []; - - expectedStructure.bids.MRI.RepetitionTime = []; - expectedStructure.bids.MRI.SliceTiming = ''; - expectedStructure.bids.MRI.TaskName = ''; - % expectedStructure.bids.MRI.PhaseEncodingDirection = ''; - % expectedStructure.bids.MRI.EffectiveEchoSpacing = ''; - % expectedStructure.bids.MRI.EchoTime = ''; - expectedStructure.bids.MRI.Instructions = ''; - expectedStructure.bids.MRI.TaskDescription = ''; - expectedStructure.bids.datasetDescription.Name = ''; expectedStructure.bids.datasetDescription.BIDSVersion = ''; expectedStructure.bids.datasetDescription.License = ''; @@ -92,6 +101,39 @@ function test_checkCFG() expectedStructure.bids.datasetDescription.Funding = {''}; expectedStructure.bids.datasetDescription.ReferencesAndLinks = {''}; expectedStructure.bids.datasetDescription.DatasetDOI = ''; - + expectedStructure = orderfields(expectedStructure); + end + + +function testSubFields(expectedStructure, cfg) + % check that that the structures match + % if it fails it check from which subfield the error comes from + + try + + assert(isequal(expectedStructure, cfg)); + + catch ME + + if isstruct(expectedStructure) + + names = fieldnames(expectedStructure); + + for i = 1:numel(names) + + disp(names{i}) + testSubFields(expectedStructure.(names{i}), cfg.(names{i})) + + end + + end + + expectedStructure + cfg + + rethrow(ME) + end +end + From c913d6c2265fe7358417e10eebe323e309e4e183 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 28 Jul 2020 19:36:54 +0200 Subject: [PATCH 07/22] adapt changes in createFilename to the new cfg --- checkCFG.m | 11 ++++- createFilename.m | 99 +++++++++++++++++++------------------ subfun/setDefaultFields.m | 4 ++ tests/test_checkCFG.m | 3 ++ tests/test_createFilename.m | 42 ++++++++-------- 5 files changed, 88 insertions(+), 71 deletions(-) diff --git a/checkCFG.m b/checkCFG.m index db9d6d6d..24565e5f 100644 --- a/checkCFG.m +++ b/checkCFG.m @@ -12,6 +12,9 @@ fieldsToSet.verbose = false; + cfg.fileName.zeroPadding = 3; + cfg.fileName.dateFormat = 'yyyymmddHHMM'; + fieldsToSet.dir.output = fullfile( ... fileparts(mfilename('fullpath')), ... '..', ... @@ -56,6 +59,8 @@ fieldsToSet.fileName.mri.echo = []; % echo fMRI images fieldsToSet.fileName.mri.acq = []; % acquisition of fMRI images + fieldsToSet.fileName.mri = orderfields(fieldsToSet.fileName.mri); + end function fieldsToSet = datasetDescriptionDefaults(fieldsToSet) @@ -97,7 +102,7 @@ fieldsToSet.bids.datasetDescription.DatasetDOI = ''; % sort fields alphabetically - fieldsToSet = orderfields(fieldsToSet); + fieldsToSet.bids.datasetDescription = orderfields(fieldsToSet.bids.datasetDescription); end @@ -143,6 +148,8 @@ % fieldsToSet.EffectiveEchoSpacing = []; % fieldsToSet.EchoTime = []; + fieldsToSet.bids.mri = orderfields(fieldsToSet.bids.mri); + end function fieldsToSet = megJsonDefaults(fieldsToSet) @@ -180,6 +187,8 @@ % outlining the scalp/face surface are contained within this recording fieldsToSet.bids.meg.DigitizedHeadPoints = []; + fieldsToSet.bids.meg = orderfields(fieldsToSet.bids.meg); + end diff --git a/createFilename.m b/createFilename.m index 61f080af..0dc5f7b3 100644 --- a/createFilename.m +++ b/createFilename.m @@ -1,9 +1,9 @@ function cfg = createFilename(cfg) - % create the BIDS compliant directories and filenames for the behavioral output + % create the BIDS compliant directories and fileNames for the behavioral output % for this subject / session / run using the information from cfg and expParameters. - % Will also create the right filename for the eyetracking data file. + % Will also create the right fileName for the eyetracking data file. % - % For the moment the date of acquisition is appended to the filename + % For the moment the date of acquisition is appended to the fileName % % can work for behavioral experiment if cfg.device is set to 'PC' % can work for fMRI experiment if cfg.device is set to 'scanner' @@ -12,17 +12,13 @@ % % See test_createFilename in the test folder for more details on how to use it. - zeroPadding = 3; - pattern = ['%0' num2str(zeroPadding) '.0f']; - cfg.pattern = pattern; - - dateFormat = 'yyyymmddHHMM'; - cfg.date = datestr(now, dateFormat); - cfg = checkCFG(cfg); + + cfg.fileName.pattern = ['%0' num2str(cfg.fileName.zeroPadding) '.0f']; + cfg.fileName.date = datestr(now, cfg.fileName.dateFormat); if ~isfield(cfg, 'task') - error('createFilename: missing a task name. i.e cfg.task'); + error('createFilename: missing a task name. i.e cfg.task.name'); end cfg = getModality(cfg); @@ -36,7 +32,8 @@ talkToMe(cfg); cfg = orderfields(cfg); - cfg = orderfields(cfg); + cfg.fileName = orderfields(cfg.fileName); + cfg.dir = orderfields(cfg.dir); end @@ -57,17 +54,17 @@ modality = 'beh'; end - cfg.modality = modality; + cfg.fileName.modality = modality; end function [subjectGrp, subjectNb, sessionNb, modality, taskName] = extractInput(cfg) - subjectGrp = cfg.subjectGrp; - subjectNb = cfg.subjectNb; - sessionNb = cfg.sessionNb; - modality = cfg.modality; - taskName = cfg.task; + subjectGrp = cfg.subject.subjectGrp; + subjectNb = cfg.subject.subjectNb; + sessionNb = cfg.subject.sessionNb; + modality = cfg.fileName.modality; + taskName = cfg.task.name; if isempty(sessionNb) sessionNb = 1; @@ -79,28 +76,28 @@ [subjectGrp, subjectNb, sessionNb, modality] = extractInput(cfg); - pattern = cfg.pattern; + pattern = cfg.fileName.pattern; % output dir - cfg.subjectOutputDir = fullfile ( ... - cfg.outputDir, ... + cfg.dir.outputSubject = fullfile ( ... + cfg.dir.output, ... 'source', ... ['sub-' subjectGrp, sprintf(pattern, subjectNb)], ... ['ses-', sprintf(pattern, sessionNb)]); - [~, ~, ~] = mkdir(cfg.outputDir); - [~, ~, ~] = mkdir(cfg.subjectOutputDir); - [~, ~, ~] = mkdir(fullfile(cfg.subjectOutputDir, modality)); + [~, ~, ~] = mkdir(cfg.dir.output); + [~, ~, ~] = mkdir(cfg.dir.outputSubject); + [~, ~, ~] = mkdir(fullfile(cfg.dir.outputSubject, modality)); - if cfg.eyeTracker - [~, ~, ~] = mkdir(fullfile(cfg.subjectOutputDir, 'eyetracker')); + if cfg.eyeTracker.do + [~, ~, ~] = mkdir(fullfile(cfg.dir.outputSubject, 'eyetracker')); end end function cfg = setSuffixes(cfg) - cfg.runSuffix = ['_run-' sprintf(cfg.pattern, cfg.runNb)]; + cfg.fileName.suffix.run = ['_run-' sprintf(cfg.fileName.pattern, cfg.subject.runNb)]; % set values for the suffixes for the different fields in the BIDS name fields2Check = { ... @@ -112,33 +109,38 @@ }; for iField = 1:numel(fields2Check) - if isempty (cfg.MRI.(fields2Check{iField})) %#ok<*GFLD> - cfg.MRI.([fields2Check{iField} 'Suffix']) = ''; %#ok<*SFLD> + if isempty (cfg.fileName.mri.(fields2Check{iField})) %#ok<*GFLD> + cfg.fileName.suffix.mri.(fields2Check{iField}) = ''; %#ok<*SFLD> else - cfg.MRI.([fields2Check{iField} 'Suffix']) = ... - ['_' fields2Check{iField} '-' getfield(cfg.MRI, fields2Check{iField})]; + cfg.fileName.suffix.mri.(fields2Check{iField}) = ... + ['_' fields2Check{iField} '-' getfield(cfg.fileName.mri, fields2Check{iField})]; end end + cfg.fileName.suffix = orderfields(cfg.fileName.suffix); + end function cfg = setFilenames(cfg) [subjectGrp, subjectNb, sessionNb, modality, taskName] = extractInput(cfg); - runSuffix = cfg.runSuffix; - pattern = cfg.pattern; - acqSuffix = cfg.MRI.acqSuffix ; - ceSuffix = cfg.MRI.ceSuffix ; - dirSuffix = cfg.MRI.dirSuffix ; - recSuffix = cfg.MRI.recSuffix ; - echoSuffix = cfg.MRI.echoSuffix; + pattern = cfg.fileName.pattern; + + runSuffix = cfg.fileName.suffix.run; + acqSuffix = cfg.fileName.suffix.mri.acq ; + ceSuffix = cfg.fileName.suffix.mri.ce ; + dirSuffix = cfg.fileName.suffix.mri.dir ; + recSuffix = cfg.fileName.suffix.mri.rec ; + echoSuffix = cfg.fileName.suffix.mri.echo; + + thisDate = cfg.fileName.date; - cfg.datasetDescription.filename = fullfile ( ... - cfg.outputDir, ... + cfg.fileName.datasetDescription = fullfile ( ... + cfg.dir.output, ... 'dataset_description.json'); - % create base filename + % create base fileName fileNameBase = ... ['sub-', subjectGrp, sprintf(pattern, subjectNb), ... '_ses-', sprintf(pattern, sessionNb), ... @@ -154,22 +156,21 @@ acqSuffix, ceSuffix, ... dirSuffix, recSuffix, ... runSuffix, echoSuffix, ... - '_events_date-' cfg.date '.tsv']; + '_events_date-' thisDate '.tsv']; otherwise cfg.fileName.events = ... - [fileNameBase, runSuffix, '_events_date-' cfg.date '.tsv']; + [fileNameBase, runSuffix, '_events_date-' thisDate '.tsv']; end cfg.fileName.stim = strrep(cfg.fileName.events, 'events', 'stim'); - if cfg.eyeTracker + if cfg.eyeTracker.do cfg.fileName.eyetracker = ... [fileNameBase, acqSuffix, ... - runSuffix, '_eyetrack_date-' cfg.date '.edf']; - + runSuffix, '_eyetrack_date-' thisDate '.edf']; end end @@ -177,15 +178,15 @@ function talkToMe(cfg) fprintf(1, '\nData will be saved in this directory:\n\t%s\n', ... - fullfile(cfg.subjectOutputDir, cfg.modality)); + fullfile(cfg.dir.outputSubject, cfg.fileName.modality)); fprintf(1, '\nData will be saved in this file:\n\t%s\n', ... cfg.fileName.events); - if cfg.eyeTracker + if cfg.eyeTracker.do fprintf(1, '\nEyetracking data will be saved in this directory:\n\t%s\n', ... - fullfile(cfg.subjectOutputDir, 'eyetracker')); + fullfile(cfg.dir.outputSubject, 'eyetracker')); fprintf(1, '\nEyetracking data will be saved in this file:\n\t%s\n', ... cfg.fileName.eyetracker); diff --git a/subfun/setDefaultFields.m b/subfun/setDefaultFields.m index ad5f2644..84772639 100644 --- a/subfun/setDefaultFields.m +++ b/subfun/setDefaultFields.m @@ -3,6 +3,8 @@ % % recursively loop through the fields of a structure and sets a value if they don't exist % + + fieldsToSet = orderfields(fieldsToSet); names = fieldnames(fieldsToSet); @@ -24,6 +26,8 @@ end end + + structure = orderfields(structure); end diff --git a/tests/test_checkCFG.m b/tests/test_checkCFG.m index c01b92c1..56d00ce2 100644 --- a/tests/test_checkCFG.m +++ b/tests/test_checkCFG.m @@ -70,6 +70,9 @@ function test_checkCFG() expectedStructure.verbose = 0; + expectedStructure.fileName.zeroPadding = 3; + expectedStructure.fileName.dateFormat = 'yyyymmddHHMM'; + expectedStructure.eyeTracker.do = false; expectedStructure.fileName.mri.ce = []; diff --git a/tests/test_createFilename.m b/tests/test_createFilename.m index 620367a4..37b44c59 100644 --- a/tests/test_createFilename.m +++ b/tests/test_createFilename.m @@ -7,10 +7,10 @@ function test_createFilename() %%% set up part - cfg.subjectNb = 1; - cfg.runNb = 1; - cfg.task = 'testtask'; - cfg.outputDir = outputDir; + cfg.subject.subjectNb = 1; + cfg.subject.runNb = 1; + cfg.task.name = 'testtask'; + cfg.dir.output = outputDir; %%% run part cfg = createFilename(cfg); @@ -21,9 +21,9 @@ function test_createFilename() behDir = fullfile(outputDir, 'source', 'sub-001', 'ses-001', 'beh'); eyetrackerDir = fullfile(outputDir, 'source', 'sub-001', 'ses-001', 'eyetracker'); eventFilename = ['sub-001_ses-001_task-testtask_run-001_events_date-'... - cfg.date '.tsv']; + cfg.fileName.date '.tsv']; stimFilename = ['sub-001_ses-001_task-testtask_run-001_stim_date-'... - cfg.date '.tsv']; + cfg.fileName.date '.tsv']; % make sure the beh dir is created assert(exist(behDir, 'dir') == 7); @@ -46,14 +46,14 @@ function test_createFilename() %%% set up part - cfg.subjectGrp = 'ctrl'; - cfg.subjectNb = 2; - cfg.sessionNb = 2; - cfg.runNb = 2; - cfg.task = 'testtask'; - cfg.outputDir = outputDir; + cfg.subject.subjectGrp = 'ctrl'; + cfg.subject.subjectNb = 2; + cfg.subject.sessionNb = 2; + cfg.subject.runNb = 2; + cfg.task.name = 'testtask'; + cfg.dir.output = outputDir; - cfg.eyeTracker = true; + cfg.eyeTracker.do = true; cfg.testingDevice = 'mri'; cfg = createFilename(cfg); @@ -65,9 +65,9 @@ function test_createFilename() eyetrackerDir = fullfile(outputDir, 'source', 'sub-ctrl002', 'ses-002', 'eyetracker'); baseFilename = 'sub-ctrl002_ses-002_task-testtask'; eventFilename = ['sub-ctrl002_ses-002_task-testtask_run-002_events_date-' ... - cfg.date '.tsv']; + cfg.fileName.date '.tsv']; eyetrackerFilename = ['sub-ctrl002_ses-002_task-testtask_run-002_eyetrack_date-' ... - cfg.date '.edf']; + cfg.fileName.date '.edf']; % make sure the func dir is created assert(exist(funcDir, 'dir') == 7); @@ -89,12 +89,12 @@ function test_createFilename() %%% set up part - cfg.subjectGrp = 'blind'; - cfg.subjectNb = 3; - cfg.sessionNb = 1; - cfg.runNb = 1; - cfg.task = 'testtask'; - cfg.outputDir = outputDir; + cfg.subject.subjectGrp = 'blind'; + cfg.subject.subjectNb = 3; + cfg.subject.sessionNb = 1; + cfg.subject.runNb = 1; + cfg.task.name = 'testtask'; + cfg.dir.output = outputDir; cfg.testingDevice = 'eeg'; From ef1110311af5e97d1659a1cae1865e19f8d9c226 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 28 Jul 2020 19:42:00 +0200 Subject: [PATCH 08/22] mh autolint --- checkCFG.m | 98 +++++++++++++++---------------- createFilename.m | 10 ++-- printCreditsCppBids.m | 27 ++++----- subfun/setDefaultFields.m | 18 +++--- tests/test_checkCFG.m | 106 +++++++++++++++++----------------- tests/test_createFilename.m | 2 +- tests/test_setDefaultFields.m | 25 ++++---- 7 files changed, 141 insertions(+), 145 deletions(-) diff --git a/checkCFG.m b/checkCFG.m index 24565e5f..21a29779 100644 --- a/checkCFG.m +++ b/checkCFG.m @@ -1,114 +1,114 @@ function cfg = checkCFG(cfg) % check that we have all the fields that we need in the experiment parameters % reuses a lot of code from the BIDS starter kit - + checkCppBidsDependencies(); - + if nargin < 1 || isempty(cfg) cfg = struct(); end - + %% set the cfg defaults - + fieldsToSet.verbose = false; - + cfg.fileName.zeroPadding = 3; cfg.fileName.dateFormat = 'yyyymmddHHMM'; - + fieldsToSet.dir.output = fullfile( ... fileparts(mfilename('fullpath')), ... '..', ... 'output'); - + fieldsToSet.subject.askGrpSess = [true true]; fieldsToSet.subject.sessionNb = 1; % in case no session was provided fieldsToSet.subject.subjectGrp = ''; % in case no group was provided - + fieldsToSet.testingDevice = 'pc'; - + fieldsToSet.eyeTracker = struct(); - + fieldsToSet.eyeTracker.do = false; - + fieldsToSet = mriDefaults(fieldsToSet); - + %% BIDS - + fieldsToSet = datasetDescriptionDefaults(fieldsToSet); - + fieldsToSet = mriJsonDefaults(fieldsToSet); if isfield(cfg, 'task') && isfield(cfg.task, 'name') fieldsToSet.bids.mri.TaskName = cfg.task.name; end - + fieldsToSet = megJsonDefaults(fieldsToSet); if isfield(cfg, 'task') && isfield(cfg.task, 'name') fieldsToSet.bids.meg.TaskName = cfg.task.name; end - + cfg = setDefaultFields(cfg, fieldsToSet); - + end function fieldsToSet = mriDefaults(fieldsToSet) - + % for file naming fieldsToSet.fileName.mri.ce = []; fieldsToSet.fileName.mri.dir = []; % phase encoding direction of acquisition for fMRI fieldsToSet.fileName.mri.rec = []; % reconstruction of fMRI images fieldsToSet.fileName.mri.echo = []; % echo fMRI images fieldsToSet.fileName.mri.acq = []; % acquisition of fMRI images - + fieldsToSet.fileName.mri = orderfields(fieldsToSet.fileName.mri); - + end function fieldsToSet = datasetDescriptionDefaults(fieldsToSet) - + % REQUIRED name of the dataset fieldsToSet.bids.datasetDescription.Name = ''; - + % REQUIRED The version of the BIDS standard that was used fieldsToSet.bids.datasetDescription.BIDSVersion = ''; - + % RECOMMENDED % what license is this dataset distributed under? The % use of license name abbreviations is suggested for specifying a license. % A list of common licenses with suggested abbreviations can be found in appendix III. fieldsToSet.bids.datasetDescription.License = ''; - + % RECOMMENDED List of individuals who contributed to the % creation/curation of the dataset fieldsToSet.bids.datasetDescription.Authors = {''}; - + % RECOMMENDED who should be acknowledge in helping to collect the data fieldsToSet.bids.datasetDescription.Acknowledgements = ''; - + % RECOMMENDED Instructions how researchers using this % dataset should acknowledge the original authors. This field can also be used % to define a publication that should be cited in publications that use the % dataset. fieldsToSet.bids.datasetDescription.HowToAcknowledge = ''; - + % RECOMMENDED sources of funding (grant numbers) fieldsToSet.bids.datasetDescription.Funding = {''}; - + % RECOMMENDED a list of references to % publication that contain information on the dataset, or links. fieldsToSet.bids.datasetDescription.ReferencesAndLinks = {''}; - + % RECOMMENDED the Document Object Identifier of the dataset % (not the corresponding paper). fieldsToSet.bids.datasetDescription.DatasetDOI = ''; - + % sort fields alphabetically fieldsToSet.bids.datasetDescription = orderfields(fieldsToSet.bids.datasetDescription); - + end function fieldsToSet = mriJsonDefaults(fieldsToSet) % for json for funcfional MRI data - + % REQUIRED The time in seconds between the beginning of an acquisition of % one volume and the beginning of acquisition of the volume following it % (TR). Please note that this definition includes time between scans @@ -116,7 +116,7 @@ % This value needs to be consistent with the pixdim[4] field % (after accounting for units stored in xyzt_units field) in the NIfTI header fieldsToSet.bids.mri.RepetitionTime = []; - + % REQUIRED for sparse sequences that do not have the DelayTime field set. % This parameter is required for sparse sequences. In addition without this % parameter slice time correction will not be possible. @@ -130,65 +130,63 @@ % time for each slice. The list goes through slices along the slice axis in the % slice encoding dimension. fieldsToSet.bids.mri.SliceTiming = []; - + % REQUIRED Name of the task (for resting state use the "rest" prefix). No two tasks % should have the same name. Task label is derived from this field by % removing all non alphanumeric ([a-zA-Z0-9]) characters. fieldsToSet.bids.mri.TaskName = []; - + % RECOMMENDED Text of the instructions given to participants before the scan. % This is especially important in context of resting state fMRI and % distinguishing between eyes open and eyes closed paradigms. fieldsToSet.bids.mri.Instructions = ''; - + % RECOMMENDED Longer description of the task. fieldsToSet.bids.mri.TaskDescription = ''; - + % fieldsToSet.PhaseEncodingDirection = []; % fieldsToSet.EffectiveEchoSpacing = []; % fieldsToSet.EchoTime = []; - + fieldsToSet.bids.mri = orderfields(fieldsToSet.bids.mri); - + end function fieldsToSet = megJsonDefaults(fieldsToSet) % for json for MEG data - + % REQUIRED Name of the task (for resting state use the "rest" prefix). No two tasks % should have the same name. Task label is derived from this field by % removing all non alphanumeric ([a-zA-Z0-9]) characters. fieldsToSet.bids.meg.TaskName = []; - + % REQUIRED Sampling frequency fieldsToSet.bids.meg.SamplingFrequency = []; - + % REQUIRED Frequency (in Hz) of the power grid at the geographical location of % the MEG instrument (i.e. 50 or 60): fieldsToSet.bids.meg.PowerLineFrequency = []; - + % REQUIRED Position of the dewar during the MEG scan: "upright", "supine" or % "degrees" of angle from vertical: for example on CTF systems, % upright=15°, supine = 90°: fieldsToSet.bids.meg.DewarPosition = []; - + % REQUIRED List of temporal and/or spatial software filters applied, or ideally % key:value pairs of pre-applied software filters and their parameter % values: e.g., {"SSS": {"frame": "head", "badlimit": 7}}, % {"SpatialCompensation": {"GradientOrder": Order of the gradient % compensation}}. Write “n/a” if no software filters applied. fieldsToSet.bids.meg.SoftwareFilters = []; - + % REQUIRED Boolean (“true” or “false”) value indicating whether anatomical % landmark points (i.e. fiducials) are contained within this recording. fieldsToSet.bids.meg.DigitizedLandmarks = []; - + % REQUIRED Boolean (“true” or “false”) value indicating whether head points % outlining the scalp/face surface are contained within this recording fieldsToSet.bids.meg.DigitizedHeadPoints = []; - - fieldsToSet.bids.meg = orderfields(fieldsToSet.bids.meg); - -end + fieldsToSet.bids.meg = orderfields(fieldsToSet.bids.meg); +end diff --git a/createFilename.m b/createFilename.m index 0dc5f7b3..b444c4ec 100644 --- a/createFilename.m +++ b/createFilename.m @@ -13,7 +13,7 @@ % See test_createFilename in the test folder for more details on how to use it. cfg = checkCFG(cfg); - + cfg.fileName.pattern = ['%0' num2str(cfg.fileName.zeroPadding) '.0f']; cfg.fileName.date = datestr(now, cfg.fileName.dateFormat); @@ -30,7 +30,7 @@ cfg = setFilenames(cfg); talkToMe(cfg); - + cfg = orderfields(cfg); cfg.fileName = orderfields(cfg.fileName); cfg.dir = orderfields(cfg.dir); @@ -118,7 +118,7 @@ end cfg.fileName.suffix = orderfields(cfg.fileName.suffix); - + end function cfg = setFilenames(cfg) @@ -126,14 +126,14 @@ [subjectGrp, subjectNb, sessionNb, modality, taskName] = extractInput(cfg); pattern = cfg.fileName.pattern; - + runSuffix = cfg.fileName.suffix.run; acqSuffix = cfg.fileName.suffix.mri.acq ; ceSuffix = cfg.fileName.suffix.mri.ce ; dirSuffix = cfg.fileName.suffix.mri.dir ; recSuffix = cfg.fileName.suffix.mri.rec ; echoSuffix = cfg.fileName.suffix.mri.echo; - + thisDate = cfg.fileName.date; cfg.fileName.datasetDescription = fullfile ( ... diff --git a/printCreditsCppBids.m b/printCreditsCppBids.m index 678130c8..bfb3f252 100644 --- a/printCreditsCppBids.m +++ b/printCreditsCppBids.m @@ -1,16 +1,18 @@ function printCreditsCppBids() - + version = '0.0.1'; - + contributors = { ... 'Rémi Gau', ... 'Marco Barilari', ... 'Ceren Battal'}; - + % DOI_URL = 'https://doi.org/10.5281/zenodo.3554331.'; - + repoURL = 'https://github.com/cpp-lln-lab/CPP_BIDS'; - + + fprintf('\n\n'); + disp('___________________________________________________'); disp('___________________________________________________'); disp(' '); @@ -19,25 +21,24 @@ function printCreditsCppBids() disp(' | (__| _/ _/ | _ \| || |) \__ \'); disp(' \___|_| |_| |___/___|___/|___/'); disp(' '); - - + splash = 'Thank you for using the CPP BIDS - version %s. '; fprintf(splash, version); fprintf('\n\n'); - + fprintf('Current list of contributors includes:\n'); for iCont = 1:numel(contributors) fprintf(' %s\n', contributors{iCont}); end fprintf('\b\n\n'); - + % fprintf('Please cite using the following DOI: \n %s\n\n', DOI_URL) - + fprintf('For bug report, suggestions or contributions see: \n %s\n\n', repoURL); - + disp('___________________________________________________'); disp('___________________________________________________'); - + fprintf('\n\n'); - + end diff --git a/subfun/setDefaultFields.m b/subfun/setDefaultFields.m index 84772639..e54f805f 100644 --- a/subfun/setDefaultFields.m +++ b/subfun/setDefaultFields.m @@ -3,7 +3,7 @@ % % recursively loop through the fields of a structure and sets a value if they don't exist % - + fieldsToSet = orderfields(fieldsToSet); names = fieldnames(fieldsToSet); @@ -11,22 +11,22 @@ for i = 1:numel(names) thisField = fieldsToSet.(names{i}); - + if isfield(structure, names{i}) && isstruct(structure.(names{i})) - + structure.(names{i}) = ... setDefaultFields(structure.(names{i}), fieldsToSet.(names{i})); - + else - structure = setFieldToIfNotPresent( ... - structure, ... - names{i}, ... - thisField); + structure = setFieldToIfNotPresent( ... + structure, ... + names{i}, ... + thisField); end end - + structure = orderfields(structure); end diff --git a/tests/test_checkCFG.m b/tests/test_checkCFG.m index 56d00ce2..5e511fd5 100644 --- a/tests/test_checkCFG.m +++ b/tests/test_checkCFG.m @@ -1,92 +1,92 @@ function test_checkCFG() - + cfg.dir.output = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); cfg = checkCFG(cfg); - + expectedStructure = returnExpectedStructure(); expectedStructure.dir.output = cfg.dir.output; expectedStructure.testingDevice = 'pc'; - - testSubFields(expectedStructure, cfg) - + + testSubFields(expectedStructure, cfg); + %% fprintf('\n--------------------------------------------------------------------'); - + clear; - + outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); - + cfg.subject.subjectNb = 1; cfg.subject.runNb = 1; - + cfg.task.name = 'testtask'; - + cfg.dir.output = outputDir; - + cfg.bids.datasetDescription.Name = 'dummy'; cfg.bids.datasetDescription.BIDSVersion = '1.0.0'; cfg.bids.datasetDescription.Authors = {'Jane Doe', 'John Doe'}; - + cfg.bids.mri.RepetitionTime = 1.56; - + cfg.testingDevice = 'mri'; - + cfg = checkCFG(cfg); - + %%% test - + % test data expectedStructure = returnExpectedStructure(); expectedStructure.subject.subjectNb = 1; expectedStructure.subject.runNb = 1; - + expectedStructure.dir.output = outputDir; - + expectedStructure.task.name = 'testtask'; expectedStructure.testingDevice = 'mri'; - + expectedStructure.bids.mri.RepetitionTime = 1.56; expectedStructure.bids.mri.TaskName = 'testtask'; - + expectedStructure.bids.meg.TaskName = 'testtask'; - + expectedStructure.bids.datasetDescription.Name = 'dummy'; expectedStructure.bids.datasetDescription.BIDSVersion = '1.0.0'; expectedStructure.bids.datasetDescription.Authors = {'Jane Doe', 'John Doe'}; - + expectedStructure = orderfields(expectedStructure); - - testSubFields(expectedStructure, cfg) - + + testSubFields(expectedStructure, cfg); + fprintf('\n'); - + end function expectedStructure = returnExpectedStructure() - + expectedStructure.subject.subjectGrp = ''; expectedStructure.subject.sessionNb = 1; expectedStructure.subject.askGrpSess = [true true]; - + expectedStructure.verbose = 0; - + expectedStructure.fileName.zeroPadding = 3; expectedStructure.fileName.dateFormat = 'yyyymmddHHMM'; - + expectedStructure.eyeTracker.do = false; - + expectedStructure.fileName.mri.ce = []; expectedStructure.fileName.mri.dir = []; expectedStructure.fileName.mri.rec = []; expectedStructure.fileName.mri.echo = []; expectedStructure.fileName.mri.acq = []; - + expectedStructure.bids.mri.RepetitionTime = []; expectedStructure.bids.mri.SliceTiming = ''; expectedStructure.bids.mri.TaskName = ''; expectedStructure.bids.mri.Instructions = ''; expectedStructure.bids.mri.TaskDescription = ''; - + expectedStructure.bids.meg.TaskName = ''; expectedStructure.bids.meg.SamplingFrequency = []; expectedStructure.bids.meg.PowerLineFrequency = []; @@ -94,7 +94,7 @@ function test_checkCFG() expectedStructure.bids.meg.SoftwareFilters = []; expectedStructure.bids.meg.DigitizedLandmarks = []; expectedStructure.bids.meg.DigitizedHeadPoints = []; - + expectedStructure.bids.datasetDescription.Name = ''; expectedStructure.bids.datasetDescription.BIDSVersion = ''; expectedStructure.bids.datasetDescription.License = ''; @@ -104,39 +104,37 @@ function test_checkCFG() expectedStructure.bids.datasetDescription.Funding = {''}; expectedStructure.bids.datasetDescription.ReferencesAndLinks = {''}; expectedStructure.bids.datasetDescription.DatasetDOI = ''; - + expectedStructure = orderfields(expectedStructure); - -end +end function testSubFields(expectedStructure, cfg) % check that that the structures match % if it fails it check from which subfield the error comes from - + try - + assert(isequal(expectedStructure, cfg)); - + catch ME - + if isstruct(expectedStructure) - + names = fieldnames(expectedStructure); - + for i = 1:numel(names) - - disp(names{i}) - testSubFields(expectedStructure.(names{i}), cfg.(names{i})) - + + disp(names{i}); + testSubFields(expectedStructure.(names{i}), cfg.(names{i})); + end - + end - - expectedStructure - cfg - - rethrow(ME) + + expectedStructure; + cfg; + + rethrow(ME); end end - diff --git a/tests/test_createFilename.m b/tests/test_createFilename.m index 37b44c59..ccde9855 100644 --- a/tests/test_createFilename.m +++ b/tests/test_createFilename.m @@ -98,7 +98,7 @@ function test_createFilename() cfg.testingDevice = 'eeg'; - cfg = createFilename(cfg); + cfg = createFilename(cfg); %%% test part diff --git a/tests/test_setDefaultFields.m b/tests/test_setDefaultFields.m index 9897938f..b0aea0fc 100644 --- a/tests/test_setDefaultFields.m +++ b/tests/test_setDefaultFields.m @@ -1,30 +1,29 @@ function test_setDefaultFields() - + structure = struct(); - + fieldsToSet.field = 1; - + structure = setDefaultFields(structure, fieldsToSet); expectedStructure.field = 1; - + assert(isequal(expectedStructure, structure)); - + fprintf('\n--------------------------------------------------------------------'); - - clear - + + clear; + structure.field.subfield_1 = 3; - + fieldsToSet.field.subfield_1 = 1; fieldsToSet.field.subfield_2 = 1; - + structure = setDefaultFields(structure, fieldsToSet); - + expectedStructure.field.subfield_1 = 3; expectedStructure.field.subfield_2 = 1; - + assert(isequal(expectedStructure, structure)); end - From 45ee30055638c469723ae37b15de2e509982d873 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 28 Jul 2020 20:25:30 +0200 Subject: [PATCH 09/22] move manual tests to a different folder --- tests/manualTests/miss_hit.cfg | 3 +++ .../test_makeRawDataset.m} | 2 +- tests/{userInput_test.m => manualTests/test_userInput.m} | 0 3 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 tests/manualTests/miss_hit.cfg rename tests/{testmanual_makeRawDataset.m => manualTests/test_makeRawDataset.m} (98%) rename tests/{userInput_test.m => manualTests/test_userInput.m} (100%) diff --git a/tests/manualTests/miss_hit.cfg b/tests/manualTests/miss_hit.cfg new file mode 100644 index 00000000..074b1ea7 --- /dev/null +++ b/tests/manualTests/miss_hit.cfg @@ -0,0 +1,3 @@ +line_length: 100 +regex_function_name: "(test_[a-z]+)(([A-Z]){1}[A-Za-z]+)*" +suppress_rule: "copyright_notice" \ No newline at end of file diff --git a/tests/testmanual_makeRawDataset.m b/tests/manualTests/test_makeRawDataset.m similarity index 98% rename from tests/testmanual_makeRawDataset.m rename to tests/manualTests/test_makeRawDataset.m index a1929f3a..ee6b5e53 100644 --- a/tests/testmanual_makeRawDataset.m +++ b/tests/manualTests/test_makeRawDataset.m @@ -33,7 +33,7 @@ function testmanual_makeRawDataset() %%% do stuff - cfg = createFilename(cfg); + cfg = createFilename(cfg); % create the events file and header logFile = saveEventsFile('open', cfg, logFile); diff --git a/tests/userInput_test.m b/tests/manualTests/test_userInput.m similarity index 100% rename from tests/userInput_test.m rename to tests/manualTests/test_userInput.m From 91fbfc5494d79771206b541fcaa30a48438c234f Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 28 Jul 2020 20:26:23 +0200 Subject: [PATCH 10/22] adapt the json creating functions to the new cfg --- createBoldJson.m | 6 +++--- createDataDictionary.m | 4 ++-- createDatasetDescription.m | 2 +- tests/test_createBoldJson.m | 14 +++++++------- tests/test_createDataDictionary.m | 10 +++++----- tests/test_createDatasetDescription.m | 5 ++--- 6 files changed, 20 insertions(+), 21 deletions(-) diff --git a/createBoldJson.m b/createBoldJson.m index 4d3b7b8f..b6325fa0 100644 --- a/createBoldJson.m +++ b/createBoldJson.m @@ -6,11 +6,11 @@ function createBoldJson(cfg) fileName = strrep(fileName, '.tsv', '.json'); fileName = fullfile( ... - cfg.subjectOutputDir, ... - cfg.modality, ... + cfg.dir.outputSubject, ... + cfg.fileName.modality, ... fileName); - jsonContent = cfg.bids.MRI; + jsonContent = cfg.bids.mri; bids.util.jsonencode(fileName, jsonContent, opts); diff --git a/createDataDictionary.m b/createDataDictionary.m index c4d59fe3..d9b6d225 100644 --- a/createDataDictionary.m +++ b/createDataDictionary.m @@ -5,8 +5,8 @@ function createDataDictionary(cfg, logFile) fileName = strrep(cfg.fileName.events, '.tsv', '.json'); fileName = fullfile( ... - cfg.subjectOutputDir, ... - cfg.modality, ... + cfg.dir.outputSubject, ... + cfg.fileName.modality, ... fileName); jsonContent = struct( ... diff --git a/createDatasetDescription.m b/createDatasetDescription.m index 507ca831..0ead3aee 100644 --- a/createDatasetDescription.m +++ b/createDatasetDescription.m @@ -3,7 +3,7 @@ function createDatasetDescription(cfg) opts.Indent = ' '; fileName = fullfile( ... - cfg.outputDir, 'source', ... + cfg.dir.output, 'source', ... 'dataset_description.json'); jsonContent = cfg.bids.datasetDescription; diff --git a/tests/test_createBoldJson.m b/tests/test_createBoldJson.m index 6d461384..72348bfa 100644 --- a/tests/test_createBoldJson.m +++ b/tests/test_createBoldJson.m @@ -4,15 +4,15 @@ function test_createBoldJson() %%% set up part - cfg.subjectNb = 1; - cfg.runNb = 1; - cfg.task = 'testtask'; - cfg.outputDir = outputDir; + cfg.subject.subjectNb = 1; + cfg.subject.runNb = 1; + cfg.task.name = 'testtask'; + cfg.dir.output = outputDir; - %cfg = struct(); + % cfg = struct(); cfg.testingDevice = 'mri'; - cfg = createFilename(cfg); + cfg = createFilename(cfg); logFile = saveEventsFile('init', cfg); %#ok<*NASGU> @@ -23,7 +23,7 @@ function test_createBoldJson() % test data funcDir = fullfile(outputDir, 'source', 'sub-001', 'ses-001', 'func'); eventFilename = ['sub-001_ses-001_task-testtask_run-001_bold_date-' ... - cfg.date '.json']; + cfg.fileName.date '.json']; % check that the file has the right path and name assert(exist(fullfile(funcDir, eventFilename), 'file') == 2); diff --git a/tests/test_createDataDictionary.m b/tests/test_createDataDictionary.m index 53e14ee5..c9bf1a81 100644 --- a/tests/test_createDataDictionary.m +++ b/tests/test_createDataDictionary.m @@ -6,10 +6,10 @@ function test_createDataDictionary() %%% set up part - cfg.subjectNb = 1; - cfg.runNb = 1; - cfg.task = 'testtask'; - cfg.outputDir = outputDir; + cfg.subject.subjectNb = 1; + cfg.subject.runNb = 1; + cfg.task.name = 'testtask'; + cfg.dir.output = outputDir; cfg.testingDevice = 'mri'; @@ -26,7 +26,7 @@ function test_createDataDictionary() % test data funcDir = fullfile(outputDir, 'source', 'sub-001', 'ses-001', 'func'); jsonFilename = ['sub-001_ses-001_task-testtask_run-001_events_date-' ... - cfg.date '.json']; + cfg.fileName.date '.json']; % check that the file has the right path and name assert(exist(fullfile(funcDir, jsonFilename), 'file') == 2); diff --git a/tests/test_createDatasetDescription.m b/tests/test_createDatasetDescription.m index 90a38335..629fe432 100644 --- a/tests/test_createDatasetDescription.m +++ b/tests/test_createDatasetDescription.m @@ -4,15 +4,14 @@ function test_createDatasetDescription() %%% set up part - cfg.outputDir = outputDir; + cfg.dir.output = outputDir; cfg.bids.datasetDescription.json.Name = 'dummy_dataset'; cfg.bids.datasetDescription.json.BIDSVersion = '1.0.0'; cfg.bids.datasetDescription.json.License = 'none'; cfg.bids.datasetDescription.json.Authors = {'Jane Doe'}; - - cfg = checkCFG(cfg); + cfg = checkCFG(cfg); createDatasetDescription(cfg); From 209d85ef8f205cf474c8474463bad7ead8d60916 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 28 Jul 2020 20:26:42 +0200 Subject: [PATCH 11/22] small changes --- checkCppBidsDependencies.m | 6 +++--- userInputs.m | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/checkCppBidsDependencies.m b/checkCppBidsDependencies.m index 5daff764..de16d169 100644 --- a/checkCppBidsDependencies.m +++ b/checkCppBidsDependencies.m @@ -1,13 +1,13 @@ function checkCppBidsDependencies pth = fileparts(mfilename('fullpath')); - + checkSubmodule(fullfile(pth, 'lib', 'JSONio')); checkSubmodule(fullfile(pth, 'lib', 'bids-matlab')); - + addpath(fullfile(pth, 'lib', 'utils')); addpath(fullfile(pth, 'subfun')); - + printCreditsCppBids(); end diff --git a/userInputs.m b/userInputs.m index d7c055d9..12bc82e9 100644 --- a/userInputs.m +++ b/userInputs.m @@ -16,8 +16,8 @@ end askGrpSess = [true true]; - if isfield(cfg, 'askGrpSess') && ~isempty(cfg.askGrpSess) - askGrpSess = cfg.askGrpSess; + if isfield(cfg, 'askGrpSess') && ~isempty(cfg.subject.askGrpSess) + askGrpSess = cfg.subject.askGrpSess; end if numel(askGrpSess) < 2 askGrpSess(2) = 1; @@ -59,10 +59,10 @@ end - cfg.subjectGrp = subjectGrp; - cfg.subjectNb = subjectNb; - cfg.sessionNb = sessionNb; - cfg.runNb = runNb; + cfg.subject.subjectGrp = subjectGrp; + cfg.subject.subjectNb = subjectNb; + cfg.subject.sessionNb = sessionNb; + cfg.subject.runNb = runNb; end From 89897cef86726b20bbacc2fc187eab2d3475fe74 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 28 Jul 2020 21:48:53 +0200 Subject: [PATCH 12/22] update usrIputs --- tests/manualTests/test_userInput.m | 26 +++++++++++++++++--------- userInputs.m | 2 +- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/tests/manualTests/test_userInput.m b/tests/manualTests/test_userInput.m index b8fa2846..6c2da3a4 100644 --- a/tests/manualTests/test_userInput.m +++ b/tests/manualTests/test_userInput.m @@ -1,33 +1,41 @@ +clear +clc + %% +fprintf('Debug\n') cfg.debug = true; cfg = userInputs(cfg); -disp(cfg); +disp(cfg.subject); %% +fprintf('No Group\n') cfg.debug = false; -cfg.askGrpSess = 0; +cfg.subject.askGrpSess = 0; cfg = userInputs(cfg); -disp(cfg); +disp(cfg.subject); %% +fprintf('No Group or session\n') cfg.debug = false; -cfg.askGrpSess = [0 0]; +cfg.subject.askGrpSess = [0 0]; cfg = userInputs(cfg); -disp(cfg); +disp(cfg.subject); %% +fprintf('No session\n') cfg.debug = false; -cfg.askGrpSess = [0 1]; +cfg.subject.askGrpSess = [1 0]; cfg = userInputs(cfg); -disp(cfg); +disp(cfg.subject); %% +fprintf('Default\n') cfg.debug = false; -cfg.askGrpSess = []; +cfg.subject.askGrpSess = []; cfg = userInputs(cfg); -disp(cfg); +disp(cfg.subject); diff --git a/userInputs.m b/userInputs.m index 12bc82e9..8e18ddee 100644 --- a/userInputs.m +++ b/userInputs.m @@ -16,7 +16,7 @@ end askGrpSess = [true true]; - if isfield(cfg, 'askGrpSess') && ~isempty(cfg.subject.askGrpSess) + if isfield(cfg, 'subject') && isfield(cfg.subject, 'askGrpSess') && ~isempty(cfg.subject.askGrpSess) askGrpSess = cfg.subject.askGrpSess; end if numel(askGrpSess) < 2 From 3f55efd3dc318100d4cdbafc1f3a2a9ccd7d3173 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 28 Jul 2020 21:49:31 +0200 Subject: [PATCH 13/22] update saveEvents to new cfg --- saveEventsFile.m | 8 +-- tests/test_saveEventsFileInit.m | 4 +- tests/test_saveEventsFileOpen.m | 38 +++++------ tests/test_saveEventsFileOpenMultiColumn.m | 48 +++++++------- tests/test_saveEventsFileSave.m | 73 +++++++++++----------- 5 files changed, 85 insertions(+), 86 deletions(-) diff --git a/saveEventsFile.m b/saveEventsFile.m index deb30ece..ae85eba7 100644 --- a/saveEventsFile.m +++ b/saveEventsFile.m @@ -116,8 +116,8 @@ fprintf(1, '\nData were saved in this file:\n\n%s\n\n', ... fullfile( ... - cfg.subjectOutputDir, ... - cfg.modality, ... + cfg.dir.outputSubject, ... + cfg.fileName.modality, ... logFile.filename)); otherwise @@ -179,8 +179,8 @@ % event file logFile.fileID = fopen( ... fullfile( ... - cfg.subjectOutputDir, ... - cfg.modality, ... + cfg.dir.outputSubject, ... + cfg.fileName.modality, ... logFile.filename), ... 'w'); diff --git a/tests/test_saveEventsFileInit.m b/tests/test_saveEventsFileInit.m index bf0a1daa..ca0ecf02 100644 --- a/tests/test_saveEventsFileInit.m +++ b/tests/test_saveEventsFileInit.m @@ -21,7 +21,7 @@ function test_saveEventsFileInit() clear; %%% set up - cfg = checkCFG(); + cfg = checkCFG(); logFile.extraColumns = {'Speed'}; %%% do stuff @@ -42,7 +42,7 @@ function test_saveEventsFileInit() clear; %%% set up - cfg = checkCFG(); + cfg = checkCFG(); logFile.extraColumns.Speed.length = 1; logFile.extraColumns.LHL24.length = 3; diff --git a/tests/test_saveEventsFileOpen.m b/tests/test_saveEventsFileOpen.m index f8b38a07..91482597 100644 --- a/tests/test_saveEventsFileOpen.m +++ b/tests/test_saveEventsFileOpen.m @@ -7,10 +7,10 @@ function test_saveEventsFileOpen() %%% set up - cfg.subjectNb = 1; - cfg.runNb = 1; - cfg.task = 'testtask'; - cfg.outputDir = outputDir; + cfg.subject.subjectNb = 1; + cfg.subject.runNb = 1; + cfg.task.name = 'testtask'; + cfg.dir.output = outputDir; cfg.testingDevice = 'mri'; @@ -29,14 +29,13 @@ function test_saveEventsFileOpen() % test data funcDir = fullfile(outputDir, 'source', 'sub-001', 'ses-001', 'func'); eventFilename = ['sub-001_ses-001_task-testtask_run-001_events_date-' ... - cfg.date '.tsv']; - - % open the file - FID = fopen(fullfile(funcDir, eventFilename), 'r'); - C = textscan(FID, repmat('%s', 1, 3), 'Delimiter', '\t', 'EndOfLine', '\n'); + cfg.fileName.date '.tsv']; % check that the file has the right path and name assert(exist(fullfile(funcDir, eventFilename), 'file') == 2); + + FID = fopen(fullfile(funcDir, eventFilename), 'r'); + C = textscan(FID, repmat('%s', 1, 3), 'Delimiter', '\t', 'EndOfLine', '\n'); % check the extra columns of the header assert(isequal(C{1}{1}, 'onset')); @@ -52,10 +51,10 @@ function test_saveEventsFileOpen() %%% set up - cfg.subjectNb = 1; - cfg.runNb = 1; - cfg.task = 'testtask'; - cfg.outputDir = outputDir; + cfg.subject.subjectNb = 1; + cfg.subject.runNb = 1; + cfg.task.name = 'testtask'; + cfg.dir.output = outputDir; cfg.testingDevice = 'mri'; @@ -64,7 +63,7 @@ function test_saveEventsFileOpen() %%% do stuff - cfg = createFilename(cfg); + cfg = createFilename(cfg); % create the events file and header logFile = saveEventsFile('open', cfg, logFile); @@ -75,12 +74,11 @@ function test_saveEventsFileOpen() %%% test section % open the file + funcDir = fullfile(cfg.dir.outputSubject, cfg.fileName.modality); + eventFilename = cfg.fileName.events; + nbExtraCol = 2; - FID = fopen(fullfile( ... - cfg.subjectOutputDir, ... - cfg.modality, ... - cfg.fileName.events), ... - 'r'); + FID = fopen(fullfile(funcDir, eventFilename), 'r'); C = textscan(FID, repmat('%s', 1, nbExtraCol + 3), 'Delimiter', '\t', 'EndOfLine', '\n'); % check the extra columns of the header @@ -89,5 +87,7 @@ function test_saveEventsFileOpen() assert(isequal(C{3}{1}, 'trial_type')); assert(isequal(C{4}{1}, 'Speed')); assert(isequal(C{5}{1}, 'is_Fixation')); + + end diff --git a/tests/test_saveEventsFileOpenMultiColumn.m b/tests/test_saveEventsFileOpenMultiColumn.m index c225643b..5a5b1682 100644 --- a/tests/test_saveEventsFileOpenMultiColumn.m +++ b/tests/test_saveEventsFileOpenMultiColumn.m @@ -1,53 +1,53 @@ function test_saveEventsFileOpenMultiColumn() - + %% check header writing with several columns for one variable clear; - + outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); - + %%% set up - - cfg.subjectNb = 1; - cfg.runNb = 1; - cfg.task = 'testtask'; - cfg.outputDir = outputDir; - + + cfg.subject.subjectNb = 1; + cfg.subject.runNb = 1; + cfg.task.name = 'testtask'; + cfg.dir.output = outputDir; + cfg.testingDevice = 'mri'; - - cfg = createFilename(cfg); - + + cfg = createFilename(cfg); + % define the extra columns: here we specify how many columns we want for % each variable logFile.extraColumns.Speed.length = 1; % will set 1 columns with name Speed logFile.extraColumns.LHL24.length = 12; % will set 12 columns with names LHL24-01, LHL24-02, ... logFile.extraColumns.is_Fixation = []; % will set 1 columns with name is_Fixation - + %%% do stuff - + % create the events file and header logFile = saveEventsFile('open', cfg, logFile); - + % close the file saveEventsFile('close', cfg, logFile); - + %%% test section - + % check the extra columns of the header and some of the content + funcDir = fullfile(cfg.dir.outputSubject, cfg.fileName.modality); + eventFilename = cfg.fileName.events; + nbExtraCol = ... logFile(1).extraColumns.Speed.length + ... logFile(1).extraColumns.LHL24.length + ... logFile(1).extraColumns.is_Fixation.length; - FID = fopen(fullfile( ... - cfg.subjectOutputDir, ... - cfg.modality, ... - cfg.fileName.events), ... - 'r'); + + FID = fopen(fullfile(funcDir, eventFilename), 'r'); C = textscan(FID, repmat('%s', 1, nbExtraCol + 3), 'Delimiter', '\t', 'EndOfLine', '\n'); - + % check the extra columns of the header assert(isequal(C{4}{1}, 'Speed')); assert(isequal(C{5}{1}, 'LHL24_01')); assert(isequal(C{16}{1}, 'LHL24_12')); assert(isequal(C{17}{1}, 'is_Fixation')); - + end diff --git a/tests/test_saveEventsFileSave.m b/tests/test_saveEventsFileSave.m index 40bfaec6..6f838af7 100644 --- a/tests/test_saveEventsFileSave.m +++ b/tests/test_saveEventsFileSave.m @@ -1,30 +1,30 @@ function test_saveEventsFileSave() - + %% write things in it clear; - + outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); - + %%% set up - - cfg.subjectNb = 1; - cfg.runNb = 1; - cfg.task = 'testtask'; - cfg.outputDir = outputDir; - + + cfg.subject.subjectNb = 1; + cfg.subject.runNb = 1; + cfg.task.name = 'testtask'; + cfg.dir.output = outputDir; + cfg.testingDevice = 'mri'; - - cfg = createFilename(cfg); - + + cfg = createFilename(cfg); + logFile.extraColumns.Speed.length = 1; logFile.extraColumns.LHL24.length = 12; logFile.extraColumns.is_Fixation.length = 1; - + % create the events file and header logFile = saveEventsFile('open', cfg, logFile); - + %%% do stuff - + % ROW 2: normal events : all info is there logFile(1, 1).onset = 2; logFile(end, 1).trial_type = 'motion_up'; @@ -32,61 +32,60 @@ function test_saveEventsFileSave() logFile(end, 1).Speed = 2; logFile(end, 1).is_Fixation = true; logFile(end, 1).LHL24 = 1:12; - + logFile = saveEventsFile('save', cfg, logFile); - + % ROW 3: missing info (speed, LHL24) logFile(1, 1).onset = 3; logFile(end, 1).trial_type = 'static'; logFile(end, 1).duration = 4; logFile(end, 1).is_Fixation = false; - + % ROW 4: missing info (duration is missing and speed is empty) logFile(2, 1).onset = 4; logFile(end, 1).trial_type = 'motion_up'; logFile(end, 1).Speed = []; logFile(end, 1).is_Fixation = true; logFile(end, 1).LHL24 = 1:12; - + % empty events logFile(3, 1).onset = []; logFile(end, 1).trial_type = []; logFile(end, 1).duration = 3; - + logFile(4, 1).onset = 1; logFile(end, 1).trial_type = ''; - + % ROW 5: missing info (array is too short) logFile(5, 1).onset = 5; logFile(end, 1).trial_type = 'jazz'; logFile(end, 1).duration = 3; logFile(end, 1).LHL24 = rand(1, 10); - + % ROW 6: too much info (array is too long) % logFile(5, 1).onset = 5; % logFile(end, 1).trial_type = 'blues'; % logFile(end, 1).duration = 3; % logFile(end, 1).LHL24 = rand(1, 15); - + saveEventsFile('save', cfg, logFile); - + % close the file saveEventsFile('close', cfg, logFile); - + %%% test section - + % check the extra columns of the header and some of the content nbExtraCol = ... logFile(1).extraColumns.Speed.length + ... logFile(1).extraColumns.LHL24.length + ... logFile(1).extraColumns.is_Fixation.length; - FID = fopen(fullfile( ... - cfg.subjectOutputDir, ... - cfg.modality, ... - cfg.fileName.events), ... - 'r'); + + funcDir = fullfile(cfg.dir.outputSubject, cfg.fileName.modality); + eventFilename = cfg.fileName.events; + FID = fopen(fullfile(funcDir, eventFilename), 'r'); C = textscan(FID, repmat('%s', 1, nbExtraCol + 3), 'Delimiter', '\t', 'EndOfLine', '\n'); - + % event 1/ ROW 2: check that values are entered correctly assert(isequal(C{1}{2}, sprintf('%f', 2))); assert(isequal(C{3}{2}, 'motion_up')); @@ -95,22 +94,22 @@ function test_saveEventsFileSave() assert(isequal(C{5}{2}, sprintf('%f', 1))); assert(isequal(C{16}{2}, sprintf('%f', 12))); assert(isequal(C{17}{2}, 'true')); - + % event 2 / ROW 3: missing info replaced by nans assert(isequal(C{4}{3}, 'n/a')); assert(isequal(C{5}{3}, 'n/a')); assert(isequal(C{16}{3}, 'n/a')); assert(isequal(C{17}{3}, 'false')); - + % event 3 / ROW 4: missing info (duration is missing and speed is empty) assert(isequal(C{2}{4}, 'n/a')); assert(isequal(C{4}{4}, 'n/a')); - + % event 4-5 / ROW 5-6: skip empty events assert(~isequal(C{1}{5}, 'n/a')); - + % check values entered properly assert(isequal(C{15}{5}, 'n/a')); assert(isequal(C{16}{5}, 'n/a')); - + end From 3102f658fe9b601a1a9c3516027badb716df2d69 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 28 Jul 2020 21:58:56 +0200 Subject: [PATCH 14/22] MH autofix --- tests/manualTests/test_makeRawDataset.m | 2 +- tests/manualTests/test_userInput.m | 14 +++--- tests/test_saveEventsFileOpen.m | 6 +-- tests/test_saveEventsFileOpenMultiColumn.m | 32 ++++++------- tests/test_saveEventsFileSave.m | 56 +++++++++++----------- userInputs.m | 6 ++- 6 files changed, 59 insertions(+), 57 deletions(-) diff --git a/tests/manualTests/test_makeRawDataset.m b/tests/manualTests/test_makeRawDataset.m index ee6b5e53..6cfbca72 100644 --- a/tests/manualTests/test_makeRawDataset.m +++ b/tests/manualTests/test_makeRawDataset.m @@ -1,4 +1,4 @@ -function testmanual_makeRawDataset() +function test_makeRawDataset() fprintf('\n\n--------------------------------------------------------------------\n\n'); diff --git a/tests/manualTests/test_userInput.m b/tests/manualTests/test_userInput.m index 6c2da3a4..ce3edab0 100644 --- a/tests/manualTests/test_userInput.m +++ b/tests/manualTests/test_userInput.m @@ -1,15 +1,15 @@ -clear -clc +clear; +clc; %% -fprintf('Debug\n') +fprintf('Debug\n'); cfg.debug = true; cfg = userInputs(cfg); disp(cfg.subject); %% -fprintf('No Group\n') +fprintf('No Group\n'); cfg.debug = false; cfg.subject.askGrpSess = 0; @@ -17,7 +17,7 @@ disp(cfg.subject); %% -fprintf('No Group or session\n') +fprintf('No Group or session\n'); cfg.debug = false; cfg.subject.askGrpSess = [0 0]; @@ -25,7 +25,7 @@ disp(cfg.subject); %% -fprintf('No session\n') +fprintf('No session\n'); cfg.debug = false; cfg.subject.askGrpSess = [1 0]; @@ -33,7 +33,7 @@ disp(cfg.subject); %% -fprintf('Default\n') +fprintf('Default\n'); cfg.debug = false; cfg.subject.askGrpSess = []; diff --git a/tests/test_saveEventsFileOpen.m b/tests/test_saveEventsFileOpen.m index 91482597..032f5f47 100644 --- a/tests/test_saveEventsFileOpen.m +++ b/tests/test_saveEventsFileOpen.m @@ -33,7 +33,7 @@ function test_saveEventsFileOpen() % check that the file has the right path and name assert(exist(fullfile(funcDir, eventFilename), 'file') == 2); - + FID = fopen(fullfile(funcDir, eventFilename), 'r'); C = textscan(FID, repmat('%s', 1, 3), 'Delimiter', '\t', 'EndOfLine', '\n'); @@ -76,7 +76,7 @@ function test_saveEventsFileOpen() % open the file funcDir = fullfile(cfg.dir.outputSubject, cfg.fileName.modality); eventFilename = cfg.fileName.events; - + nbExtraCol = 2; FID = fopen(fullfile(funcDir, eventFilename), 'r'); C = textscan(FID, repmat('%s', 1, nbExtraCol + 3), 'Delimiter', '\t', 'EndOfLine', '\n'); @@ -87,7 +87,5 @@ function test_saveEventsFileOpen() assert(isequal(C{3}{1}, 'trial_type')); assert(isequal(C{4}{1}, 'Speed')); assert(isequal(C{5}{1}, 'is_Fixation')); - - end diff --git a/tests/test_saveEventsFileOpenMultiColumn.m b/tests/test_saveEventsFileOpenMultiColumn.m index 5a5b1682..69b0dc5b 100644 --- a/tests/test_saveEventsFileOpenMultiColumn.m +++ b/tests/test_saveEventsFileOpenMultiColumn.m @@ -1,53 +1,53 @@ function test_saveEventsFileOpenMultiColumn() - + %% check header writing with several columns for one variable clear; - + outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); - + %%% set up - + cfg.subject.subjectNb = 1; cfg.subject.runNb = 1; cfg.task.name = 'testtask'; cfg.dir.output = outputDir; - + cfg.testingDevice = 'mri'; - + cfg = createFilename(cfg); - + % define the extra columns: here we specify how many columns we want for % each variable logFile.extraColumns.Speed.length = 1; % will set 1 columns with name Speed logFile.extraColumns.LHL24.length = 12; % will set 12 columns with names LHL24-01, LHL24-02, ... logFile.extraColumns.is_Fixation = []; % will set 1 columns with name is_Fixation - + %%% do stuff - + % create the events file and header logFile = saveEventsFile('open', cfg, logFile); - + % close the file saveEventsFile('close', cfg, logFile); - + %%% test section - + % check the extra columns of the header and some of the content funcDir = fullfile(cfg.dir.outputSubject, cfg.fileName.modality); eventFilename = cfg.fileName.events; - + nbExtraCol = ... logFile(1).extraColumns.Speed.length + ... logFile(1).extraColumns.LHL24.length + ... logFile(1).extraColumns.is_Fixation.length; - + FID = fopen(fullfile(funcDir, eventFilename), 'r'); C = textscan(FID, repmat('%s', 1, nbExtraCol + 3), 'Delimiter', '\t', 'EndOfLine', '\n'); - + % check the extra columns of the header assert(isequal(C{4}{1}, 'Speed')); assert(isequal(C{5}{1}, 'LHL24_01')); assert(isequal(C{16}{1}, 'LHL24_12')); assert(isequal(C{17}{1}, 'is_Fixation')); - + end diff --git a/tests/test_saveEventsFileSave.m b/tests/test_saveEventsFileSave.m index 6f838af7..9cc610c5 100644 --- a/tests/test_saveEventsFileSave.m +++ b/tests/test_saveEventsFileSave.m @@ -1,30 +1,30 @@ function test_saveEventsFileSave() - + %% write things in it clear; - + outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); - + %%% set up - + cfg.subject.subjectNb = 1; cfg.subject.runNb = 1; cfg.task.name = 'testtask'; cfg.dir.output = outputDir; - + cfg.testingDevice = 'mri'; - + cfg = createFilename(cfg); - + logFile.extraColumns.Speed.length = 1; logFile.extraColumns.LHL24.length = 12; logFile.extraColumns.is_Fixation.length = 1; - + % create the events file and header logFile = saveEventsFile('open', cfg, logFile); - + %%% do stuff - + % ROW 2: normal events : all info is there logFile(1, 1).onset = 2; logFile(end, 1).trial_type = 'motion_up'; @@ -32,60 +32,60 @@ function test_saveEventsFileSave() logFile(end, 1).Speed = 2; logFile(end, 1).is_Fixation = true; logFile(end, 1).LHL24 = 1:12; - + logFile = saveEventsFile('save', cfg, logFile); - + % ROW 3: missing info (speed, LHL24) logFile(1, 1).onset = 3; logFile(end, 1).trial_type = 'static'; logFile(end, 1).duration = 4; logFile(end, 1).is_Fixation = false; - + % ROW 4: missing info (duration is missing and speed is empty) logFile(2, 1).onset = 4; logFile(end, 1).trial_type = 'motion_up'; logFile(end, 1).Speed = []; logFile(end, 1).is_Fixation = true; logFile(end, 1).LHL24 = 1:12; - + % empty events logFile(3, 1).onset = []; logFile(end, 1).trial_type = []; logFile(end, 1).duration = 3; - + logFile(4, 1).onset = 1; logFile(end, 1).trial_type = ''; - + % ROW 5: missing info (array is too short) logFile(5, 1).onset = 5; logFile(end, 1).trial_type = 'jazz'; logFile(end, 1).duration = 3; logFile(end, 1).LHL24 = rand(1, 10); - + % ROW 6: too much info (array is too long) % logFile(5, 1).onset = 5; % logFile(end, 1).trial_type = 'blues'; % logFile(end, 1).duration = 3; % logFile(end, 1).LHL24 = rand(1, 15); - + saveEventsFile('save', cfg, logFile); - + % close the file saveEventsFile('close', cfg, logFile); - + %%% test section - + % check the extra columns of the header and some of the content nbExtraCol = ... logFile(1).extraColumns.Speed.length + ... logFile(1).extraColumns.LHL24.length + ... logFile(1).extraColumns.is_Fixation.length; - + funcDir = fullfile(cfg.dir.outputSubject, cfg.fileName.modality); eventFilename = cfg.fileName.events; FID = fopen(fullfile(funcDir, eventFilename), 'r'); C = textscan(FID, repmat('%s', 1, nbExtraCol + 3), 'Delimiter', '\t', 'EndOfLine', '\n'); - + % event 1/ ROW 2: check that values are entered correctly assert(isequal(C{1}{2}, sprintf('%f', 2))); assert(isequal(C{3}{2}, 'motion_up')); @@ -94,22 +94,22 @@ function test_saveEventsFileSave() assert(isequal(C{5}{2}, sprintf('%f', 1))); assert(isequal(C{16}{2}, sprintf('%f', 12))); assert(isequal(C{17}{2}, 'true')); - + % event 2 / ROW 3: missing info replaced by nans assert(isequal(C{4}{3}, 'n/a')); assert(isequal(C{5}{3}, 'n/a')); assert(isequal(C{16}{3}, 'n/a')); assert(isequal(C{17}{3}, 'false')); - + % event 3 / ROW 4: missing info (duration is missing and speed is empty) assert(isequal(C{2}{4}, 'n/a')); assert(isequal(C{4}{4}, 'n/a')); - + % event 4-5 / ROW 5-6: skip empty events assert(~isequal(C{1}{5}, 'n/a')); - + % check values entered properly assert(isequal(C{15}{5}, 'n/a')); assert(isequal(C{16}{5}, 'n/a')); - + end diff --git a/userInputs.m b/userInputs.m index 8e18ddee..8b153471 100644 --- a/userInputs.m +++ b/userInputs.m @@ -16,8 +16,12 @@ end askGrpSess = [true true]; - if isfield(cfg, 'subject') && isfield(cfg.subject, 'askGrpSess') && ~isempty(cfg.subject.askGrpSess) + if isfield(cfg, 'subject') && ... + isfield(cfg.subject, 'askGrpSess') && ... + ~isempty(cfg.subject.askGrpSess) + askGrpSess = cfg.subject.askGrpSess; + end if numel(askGrpSess) < 2 askGrpSess(2) = 1; From f70005b0e87fca3a0ec519f64eff90c309419791 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 28 Jul 2020 22:34:36 +0200 Subject: [PATCH 15/22] update converting scripts --- .travis.yml | 2 +- convertSourceToRaw.m | 12 ++++++++---- tests/manualTests/test_makeRawDataset.m | 14 +++++++------- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0cdf80af..f556c59c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,7 +36,7 @@ jobs: script: octave $OCTFLAGS --eval "results = runTests; assert(all(~[results.Failed]))" - stage: "BIDS validator" name: "Create and check dataset" - script: octave $OCTFLAGS --eval "testmanual_makeRawDataset" && bids-validator `pwd`/../output/rawdata/ --ignoreNiftiHeaders + script: cd manualTests && octave $OCTFLAGS --eval "test_makeRawDataset" && bids-validator `pwd`/../output/rawdata/ --ignoreNiftiHeaders - stage: "Linter" name: "miss_hit" script: cd .. && mh_style `pwd` diff --git a/convertSourceToRaw.m b/convertSourceToRaw.m index 4ecd5c81..433d4b5c 100644 --- a/convertSourceToRaw.m +++ b/convertSourceToRaw.m @@ -1,11 +1,15 @@ function convertSourceToRaw(cfg) - sourceDir = fullfile(cfg.outputDir, 'source'); - rawDir = fullfile(cfg.outputDir, 'rawdata'); + sourceDir = fullfile(cfg.dir.output, 'source'); + rawDir = fullfile(cfg.dir.output, 'rawdata'); % add dummy readme and change file - copyfile(fullfile('..', 'dummyData', 'README'), sourceDir); - copyfile(fullfile('..', 'dummyData', 'CHANGES'), sourceDir); + copyfile(fullfile( ... + fileparts(mfilename('fullpath')), 'dummyData', 'README'), ... + sourceDir); + copyfile(fullfile( ... + fileparts(mfilename('fullpath')), 'dummyData', 'CHANGES'), ... + sourceDir); copyfile(sourceDir, rawDir); diff --git a/tests/manualTests/test_makeRawDataset.m b/tests/manualTests/test_makeRawDataset.m index 6cfbca72..46f8a3ed 100644 --- a/tests/manualTests/test_makeRawDataset.m +++ b/tests/manualTests/test_makeRawDataset.m @@ -14,16 +14,16 @@ function test_makeRawDataset() %%% set up - cfg.subjectNb = 1; - cfg.runNb = 1; - cfg.task = 'testtask'; - cfg.outputDir = outputDir; + cfg.subject.subjectNb = 1; + cfg.subject.runNb = 1; + cfg.task.name = 'testtask'; + cfg.dir.output = outputDir; cfg.bids.datasetDescription.Name = 'dummy'; cfg.bids.datasetDescription.BIDSVersion = '1.0.0'; cfg.bids.datasetDescription.Authors = {'Jane Doe', 'John Doe'}; - cfg.bids.MRI.RepetitionTime = 1.56; + cfg.bids.mri.RepetitionTime = 1.56; cfg.testingDevice = 'mri'; @@ -74,10 +74,10 @@ function test_makeRawDataset() saveEventsFile('close', cfg, logFile); % add dummy functional data - funcDir = fullfile(cfg.outputDir, 'source', 'sub-001', 'ses-001', 'func'); + funcDir = fullfile(cfg.dir.output, 'source', 'sub-001', 'ses-001', 'func'); boldFilename = 'sub-001_ses-001_task-testtask_run-001_bold.nii.gz'; copyfile( ... - fullfile('..', 'dummyData', 'dummyData.nii.gz'), ... + fullfile('..', '..', 'dummyData', 'dummyData.nii.gz'), ... fullfile(funcDir, boldFilename)); %% From e7db055cc63d961ced4be0c141d5935720c6b358 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 28 Jul 2020 23:03:49 +0200 Subject: [PATCH 16/22] update test_makeMakeRawdata and travis --- .travis.yml | 2 +- tests/manualTests/test_makeRawDataset.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index f556c59c..22f36925 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,7 +36,7 @@ jobs: script: octave $OCTFLAGS --eval "results = runTests; assert(all(~[results.Failed]))" - stage: "BIDS validator" name: "Create and check dataset" - script: cd manualTests && octave $OCTFLAGS --eval "test_makeRawDataset" && bids-validator `pwd`/../output/rawdata/ --ignoreNiftiHeaders + script: cd manualTests && octave $OCTFLAGS --eval "test_makeRawDataset" && bids-validator `pwd`/output/rawdata/ --ignoreNiftiHeaders - stage: "Linter" name: "miss_hit" script: cd .. && mh_style `pwd` diff --git a/tests/manualTests/test_makeRawDataset.m b/tests/manualTests/test_makeRawDataset.m index 46f8a3ed..e3ca4b3d 100644 --- a/tests/manualTests/test_makeRawDataset.m +++ b/tests/manualTests/test_makeRawDataset.m @@ -4,7 +4,7 @@ function test_makeRawDataset() clear; - outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); + outputDir = fullfile(fileparts(mfilename('fullpath')), 'output'); if isdir(outputDir) rmdir(outputDir, 's'); From ecc0245f427c0486679f58c13b247172c4faa24a Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 28 Jul 2020 23:04:02 +0200 Subject: [PATCH 17/22] refactor saveEvents --- saveEventsFile.m | 96 ++++++++++++++++++++++++++---------------------- 1 file changed, 52 insertions(+), 44 deletions(-) diff --git a/saveEventsFile.m b/saveEventsFile.m index ae85eba7..76891037 100644 --- a/saveEventsFile.m +++ b/saveEventsFile.m @@ -77,35 +77,7 @@ checklLogFile('checkID', logFile); checklLogFile('type&size', logFile); - % appends to the logfile all the data stored in the structure - % first with the standard BIDS data and then any extra things - for iEvent = 1:size(logFile, 1) - - logFile = checklLogFile('fields', logFile, iEvent); - - onset = logFile(iEvent).onset; - duration = logFile(iEvent).duration; - trial_type = logFile(iEvent).trial_type; - - if isnan(onset) || ischar(onset) || any(isempty({onset trial_type})) || ... - strcmp(trial_type, 'n/a') - - warning('\nSkipping saving this event.\n onset: %f \n trial_type: %s\n', ... - onset, ... - trial_type); - - else - - printData(logFile(1).fileID, onset); - printData(logFile(1).fileID, duration); - printData(logFile(1).fileID, trial_type); - - printExtraColumns(logFile, iEvent); - - fprintf(logFile(1).fileID, '\n'); - - end - end + logFile = saveToLogFile(logFile); case 'close' @@ -153,14 +125,10 @@ case 'fields' - if ~isfield(logFile, 'onset') || isempty(logFile(iEvent).onset) - logFile(iEvent).onset = nan; - end - if ~isfield(logFile, 'trial_type') || isempty(logFile(iEvent).trial_type) - logFile(iEvent).trial_type = nan; - end - if ~isfield(logFile, 'duration') || isempty(logFile(iEvent).duration) - logFile(iEvent).duration = nan; + for iFields = {'onset', 'trial_type', 'duration'} + if ~isfield(logFile, iFields) || isempty(logFile(iEvent).(iFields{1})) + logFile(iEvent).(iFields{1}) = nan; + end end logFile = checkExtracolumns(logFile, iEvent); @@ -232,7 +200,9 @@ function printHeaderExtraColumns(logFile) data = logFile(iEvent).(namesExtraColumns{iExtraColumn}); end - data = checkInput(data, nbCol); + data = checkInput(data); + + data = nanPadding(data, nbCol); logFile(iEvent).(namesExtraColumns{iExtraColumn}) = data; @@ -248,15 +218,11 @@ function printHeaderExtraColumns(logFile) end -function data = checkInput(data, expectedLength) +function data = checkInput(data) % check the data to write % default will be 'n/a' for chars and NaN for numeric data % for numeric data that don't have the expected length, it will be padded with NaNs - if nargin < 2 - expectedLength = []; - end - if islogical(data) && data data = 'true'; elseif islogical(data) && ~data @@ -271,12 +237,54 @@ function printHeaderExtraColumns(logFile) data = nan; end +end + +function data = nanPadding(data, expectedLength) + + if nargin < 2 + expectedLength = []; + end + if ~isempty(expectedLength) && isnumeric(data) && max(size(data)) < expectedLength padding = expectedLength - max(size(data)); data(end + 1:end + padding) = nan(1, padding); elseif ~isempty(expectedLength) && isnumeric(data) && max(size(data)) > expectedLength - data = data(1:expectedLength); warning('A field for this event is longer than expected. Truncating the extra values.'); + data = data(1:expectedLength); + end + +end + +function logFile = saveToLogFile(logFile) + + % appends to the logfile all the data stored in the structure + % first with the standard BIDS data and then any extra things + for iEvent = 1:size(logFile, 1) + + logFile = checklLogFile('fields', logFile, iEvent); + + onset = logFile(iEvent).onset; + duration = logFile(iEvent).duration; + trial_type = logFile(iEvent).trial_type; + + if isnan(onset) || ischar(onset) || any(isempty({onset trial_type})) || ... + strcmp(trial_type, 'n/a') + + warning('\nSkipping saving this event.\n onset: %f \n trial_type: %s\n', ... + onset, ... + trial_type); + + else + + printData(logFile(1).fileID, onset); + printData(logFile(1).fileID, duration); + printData(logFile(1).fileID, trial_type); + + printExtraColumns(logFile, iEvent); + + fprintf(logFile(1).fileID, '\n'); + + end end end From d0b8c1dbffd2a8a7a53ada7a8f2325209fa3f902 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 28 Jul 2020 23:39:33 +0200 Subject: [PATCH 18/22] fix bad character encoding --- checkCFG.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/checkCFG.m b/checkCFG.m index 21a29779..a1caeaab 100644 --- a/checkCFG.m +++ b/checkCFG.m @@ -176,14 +176,14 @@ % key:value pairs of pre-applied software filters and their parameter % values: e.g., {"SSS": {"frame": "head", "badlimit": 7}}, % {"SpatialCompensation": {"GradientOrder": Order of the gradient - % compensation}}. Write “n/a” if no software filters applied. + % compensation}}. Write "n/a" if no software filters applied. fieldsToSet.bids.meg.SoftwareFilters = []; - % REQUIRED Boolean (“true” or “false”) value indicating whether anatomical + % REQUIRED Boolean ("true" or "false") value indicating whether anatomical % landmark points (i.e. fiducials) are contained within this recording. fieldsToSet.bids.meg.DigitizedLandmarks = []; - % REQUIRED Boolean (“true” or “false”) value indicating whether head points + % REQUIRED Boolean ("true" or "false") value indicating whether head points % outlining the scalp/face surface are contained within this recording fieldsToSet.bids.meg.DigitizedHeadPoints = []; From 8551d475db65e524cfa36f563a5b800bc21b4dfa Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Wed, 29 Jul 2020 12:59:55 +0200 Subject: [PATCH 19/22] add tests for sub functions --- subfun/createTaskName.m | 18 +++++++++++++++++ subfun/transferInfoToBids.m | 16 +++++++++++++++ tests/test_createTaskName.m | 28 ++++++++++++++++++++++++++ tests/test_transferInfoToBids.m | 35 +++++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+) create mode 100644 subfun/createTaskName.m create mode 100644 subfun/transferInfoToBids.m create mode 100644 tests/test_createTaskName.m create mode 100644 tests/test_transferInfoToBids.m diff --git a/subfun/createTaskName.m b/subfun/createTaskName.m new file mode 100644 index 00000000..754bf262 --- /dev/null +++ b/subfun/createTaskName.m @@ -0,0 +1,18 @@ +function [taskName, taskNameValid] = createTaskName(taskName) + % [taskName, taskNameValid] = createTaskName(taskName) + % + % Name of the task (for resting state use the "rest" prefix). No two tasks + % should have the same name. Task label is derived from this field by + % removing all non alphanumeric ([a-zA-Z0-9]) characters. + + % camel case: upper case for first letter for all words but the first one + spaceIdx = regexp(taskName, '[a-zA-Z0-9]*', 'start'); + taskName(spaceIdx(2:end)) = upper(taskName(spaceIdx(2:end))); + + % remove invalid characters + [unvalidCharacters] = regexp(taskName, '[^a-zA-Z0-9]'); + taskNameValid = taskName; + taskNameValid(unvalidCharacters) = []; + +end + diff --git a/subfun/transferInfoToBids.m b/subfun/transferInfoToBids.m new file mode 100644 index 00000000..4a408b56 --- /dev/null +++ b/subfun/transferInfoToBids.m @@ -0,0 +1,16 @@ +function fieldsToSet = transferInfoToBids(fieldsToSet, cfg) + % transfer any info that might have been provided by the user to the + % relevant field for its reuse for BIDS filenames or JSON later + + if isfield(cfg, 'task') && isfield(cfg.task, 'name') + [taskName, taskNameValid] = createTaskName(cfg.task.name); + fieldsToSet.fileName.task = taskNameValid; + fieldsToSet.bids.meg.TaskName = taskName; + fieldsToSet.bids.mri.TaskName = taskName; + end + + if isfield(cfg, 'mri') && isfield(cfg.mri, 'repetitionTime') + fieldsToSet.bids.mri.RepetitionTime = cfg.mri.repetitionTime; + end + +end \ No newline at end of file diff --git a/tests/test_createTaskName.m b/tests/test_createTaskName.m new file mode 100644 index 00000000..15bd44db --- /dev/null +++ b/tests/test_createTaskName.m @@ -0,0 +1,28 @@ +function test_createTaskName() + % + + taskName = '&|@#-_(§!{})[]ù%£+/=:;.?,\<> visual task'; + + [taskName, taskNameValid] = createTaskName(taskName) + + [unvalidCharacters] = regexp(taskNameValid, '[^a-zA-Z0-9]'); + + assert(isempty(unvalidCharacters)); + + + taskName = ' 09 visual task'; + + [taskName, taskNameValid] = createTaskName(taskName) + + [unvalidCharacters] = regexp(taskNameValid, '[^a-zA-Z0-9]'); + + assert(isempty(unvalidCharacters)); + + + taskName = 'foo bar'; + [taskName, taskNameValid] = createTaskName(taskName) + assert(isequal(taskName, 'foo Bar')) + assert(isequal(taskNameValid, 'fooBar')) + +end + diff --git a/tests/test_transferInfoToBids.m b/tests/test_transferInfoToBids.m new file mode 100644 index 00000000..2f8c5164 --- /dev/null +++ b/tests/test_transferInfoToBids.m @@ -0,0 +1,35 @@ +function test_transferInfoToBids() + + %% + cfg = struct(); + fieldsToSet = struct(); + cfg = transferInfoToBids(fieldsToSet, cfg); + + expectedStruct = struct(); + + assert(isequal(expectedStruct, fieldsToSet)) + + %% + cfg.task.name = 'foo bar'; + + fieldsToSet = transferInfoToBids(fieldsToSet, cfg); + + expectedStruct.fileName.task = 'fooBar'; + expectedStruct.bids.meg.TaskName = 'foo Bar'; + expectedStruct.bids.mri.TaskName = 'foo Bar'; + + assert(isequal(expectedStruct, fieldsToSet)) + + %% + clear cfg fieldsToSet expectedStruct + + cfg.mri.repetitionTime = 1.56; + + fieldsToSet = struct(); + fieldsToSet = transferInfoToBids(fieldsToSet, cfg); + + expectedStruct.bids.mri.RepetitionTime = 1.56; + + assert(isequal(expectedStruct, fieldsToSet)) + +end \ No newline at end of file From bf850d65b152833ef0e42f184b6cdcc150e1fc8f Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Wed, 29 Jul 2020 13:00:15 +0200 Subject: [PATCH 20/22] update checkCFG --- checkCFG.m | 34 +++++++++++++++------------------- tests/test_checkCFG.m | 27 +++++++++++++++++---------- 2 files changed, 32 insertions(+), 29 deletions(-) diff --git a/checkCFG.m b/checkCFG.m index a1caeaab..9d6b93d8 100644 --- a/checkCFG.m +++ b/checkCFG.m @@ -12,8 +12,9 @@ fieldsToSet.verbose = false; - cfg.fileName.zeroPadding = 3; - cfg.fileName.dateFormat = 'yyyymmddHHMM'; + fieldsToSet.fileName.task = ''; + fieldsToSet.fileName.zeroPadding = 3; + fieldsToSet.fileName.dateFormat = 'yyyymmddHHMM'; fieldsToSet.dir.output = fullfile( ... fileparts(mfilename('fullpath')), ... @@ -35,31 +36,26 @@ %% BIDS fieldsToSet = datasetDescriptionDefaults(fieldsToSet); - fieldsToSet = mriJsonDefaults(fieldsToSet); - if isfield(cfg, 'task') && isfield(cfg.task, 'name') - fieldsToSet.bids.mri.TaskName = cfg.task.name; - end - fieldsToSet = megJsonDefaults(fieldsToSet); - if isfield(cfg, 'task') && isfield(cfg.task, 'name') - fieldsToSet.bids.meg.TaskName = cfg.task.name; - end - + + fieldsToSet = transferInfoToBids(fieldsToSet, cfg); + cfg = setDefaultFields(cfg, fieldsToSet); end function fieldsToSet = mriDefaults(fieldsToSet) - % for file naming - fieldsToSet.fileName.mri.ce = []; - fieldsToSet.fileName.mri.dir = []; % phase encoding direction of acquisition for fMRI - fieldsToSet.fileName.mri.rec = []; % reconstruction of fMRI images - fieldsToSet.fileName.mri.echo = []; % echo fMRI images - fieldsToSet.fileName.mri.acq = []; % acquisition of fMRI images + % for file naming and JSON + fieldsToSet.mri.contrastEnhancement = []; + fieldsToSet.mri.phaseEncodingDirection = []; + fieldsToSet.mri.reconstruction = []; + fieldsToSet.mri.echo = []; + fieldsToSet.mri.acquisition = []; + fieldsToSet.mri.repetitionTime = []; - fieldsToSet.fileName.mri = orderfields(fieldsToSet.fileName.mri); + fieldsToSet.mri = orderfields(fieldsToSet.mri); end @@ -189,4 +185,4 @@ fieldsToSet.bids.meg = orderfields(fieldsToSet.bids.meg); -end +end \ No newline at end of file diff --git a/tests/test_checkCFG.m b/tests/test_checkCFG.m index 5e511fd5..9be6f5af 100644 --- a/tests/test_checkCFG.m +++ b/tests/test_checkCFG.m @@ -19,7 +19,7 @@ function test_checkCFG() cfg.subject.subjectNb = 1; cfg.subject.runNb = 1; - cfg.task.name = 'testtask'; + cfg.task.name = 'test task'; cfg.dir.output = outputDir; @@ -27,7 +27,7 @@ function test_checkCFG() cfg.bids.datasetDescription.BIDSVersion = '1.0.0'; cfg.bids.datasetDescription.Authors = {'Jane Doe', 'John Doe'}; - cfg.bids.mri.RepetitionTime = 1.56; + cfg.mri.repetitionTime = 1.56; cfg.testingDevice = 'mri'; @@ -42,13 +42,18 @@ function test_checkCFG() expectedStructure.dir.output = outputDir; - expectedStructure.task.name = 'testtask'; + expectedStructure.task.name = 'test task'; + expectedStructure.testingDevice = 'mri'; + expectedStructure.mri.repetitionTime = 1.56; + + expectedStructure.fileName.task = 'testTask'; + expectedStructure.bids.mri.RepetitionTime = 1.56; - expectedStructure.bids.mri.TaskName = 'testtask'; + expectedStructure.bids.mri.TaskName = 'test Task'; - expectedStructure.bids.meg.TaskName = 'testtask'; + expectedStructure.bids.meg.TaskName = 'test Task'; expectedStructure.bids.datasetDescription.Name = 'dummy'; expectedStructure.bids.datasetDescription.BIDSVersion = '1.0.0'; @@ -70,16 +75,18 @@ function test_checkCFG() expectedStructure.verbose = 0; + expectedStructure.fileName.task = ''; expectedStructure.fileName.zeroPadding = 3; expectedStructure.fileName.dateFormat = 'yyyymmddHHMM'; expectedStructure.eyeTracker.do = false; - expectedStructure.fileName.mri.ce = []; - expectedStructure.fileName.mri.dir = []; - expectedStructure.fileName.mri.rec = []; - expectedStructure.fileName.mri.echo = []; - expectedStructure.fileName.mri.acq = []; + expectedStructure.mri.contrastEnhancement = []; + expectedStructure.mri.phaseEncodingDirection = []; + expectedStructure.mri.reconstruction = []; + expectedStructure.mri.echo = []; + expectedStructure.mri.acquisition = []; + expectedStructure.mri.repetitionTime = []; expectedStructure.bids.mri.RepetitionTime = []; expectedStructure.bids.mri.SliceTiming = ''; From 2b3e6ff872c53a8512043bf9482f9886f9b5724c Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Wed, 29 Jul 2020 13:07:39 +0200 Subject: [PATCH 21/22] update createFilename --- createFilename.m | 22 +++++++++++----------- tests/test_createFilename.m | 16 ++++++++-------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/createFilename.m b/createFilename.m index b444c4ec..733ffeb1 100644 --- a/createFilename.m +++ b/createFilename.m @@ -64,7 +64,7 @@ subjectNb = cfg.subject.subjectNb; sessionNb = cfg.subject.sessionNb; modality = cfg.fileName.modality; - taskName = cfg.task.name; + taskName = cfg.fileName.task; if isempty(sessionNb) sessionNb = 1; @@ -101,19 +101,19 @@ % set values for the suffixes for the different fields in the BIDS name fields2Check = { ... - 'ce', ... - 'dir', ... % For BIDS file naming: phase encoding direction of acquisition for fMRI - 'rec', ... % For BIDS file naming: reconstruction of fMRI images + 'contrastEnhancement', ... + 'phaseEncodingDirection', ... % For BIDS file naming: phase encoding direction of acquisition for fMRI + 'reconstruction', ... % For BIDS file naming: reconstruction of fMRI images 'echo', ... % For BIDS file naming: echo fMRI images - 'acq' % For BIDS file naming: acquisition of fMRI images + 'acquisition' % For BIDS file naming: acquisition of fMRI images }; for iField = 1:numel(fields2Check) - if isempty (cfg.fileName.mri.(fields2Check{iField})) %#ok<*GFLD> + if isempty (cfg.mri.(fields2Check{iField})) %#ok<*GFLD> cfg.fileName.suffix.mri.(fields2Check{iField}) = ''; %#ok<*SFLD> else cfg.fileName.suffix.mri.(fields2Check{iField}) = ... - ['_' fields2Check{iField} '-' getfield(cfg.fileName.mri, fields2Check{iField})]; + ['_' fields2Check{iField} '-' getfield(cfg.mri, fields2Check{iField})]; end end @@ -128,10 +128,10 @@ pattern = cfg.fileName.pattern; runSuffix = cfg.fileName.suffix.run; - acqSuffix = cfg.fileName.suffix.mri.acq ; - ceSuffix = cfg.fileName.suffix.mri.ce ; - dirSuffix = cfg.fileName.suffix.mri.dir ; - recSuffix = cfg.fileName.suffix.mri.rec ; + acqSuffix = cfg.fileName.suffix.mri.acquisition ; + ceSuffix = cfg.fileName.suffix.mri.contrastEnhancement ; + dirSuffix = cfg.fileName.suffix.mri.phaseEncodingDirection ; + recSuffix = cfg.fileName.suffix.mri.reconstruction ; echoSuffix = cfg.fileName.suffix.mri.echo; thisDate = cfg.fileName.date; diff --git a/tests/test_createFilename.m b/tests/test_createFilename.m index ccde9855..641bd6e4 100644 --- a/tests/test_createFilename.m +++ b/tests/test_createFilename.m @@ -9,7 +9,7 @@ function test_createFilename() cfg.subject.subjectNb = 1; cfg.subject.runNb = 1; - cfg.task.name = 'testtask'; + cfg.task.name = 'test task'; cfg.dir.output = outputDir; %%% run part @@ -20,9 +20,9 @@ function test_createFilename() % test data behDir = fullfile(outputDir, 'source', 'sub-001', 'ses-001', 'beh'); eyetrackerDir = fullfile(outputDir, 'source', 'sub-001', 'ses-001', 'eyetracker'); - eventFilename = ['sub-001_ses-001_task-testtask_run-001_events_date-'... + eventFilename = ['sub-001_ses-001_task-testTask_run-001_events_date-'... cfg.fileName.date '.tsv']; - stimFilename = ['sub-001_ses-001_task-testtask_run-001_stim_date-'... + stimFilename = ['sub-001_ses-001_task-testTask_run-001_stim_date-'... cfg.fileName.date '.tsv']; % make sure the beh dir is created @@ -50,7 +50,7 @@ function test_createFilename() cfg.subject.subjectNb = 2; cfg.subject.sessionNb = 2; cfg.subject.runNb = 2; - cfg.task.name = 'testtask'; + cfg.task.name = 'testTask'; cfg.dir.output = outputDir; cfg.eyeTracker.do = true; @@ -63,10 +63,10 @@ function test_createFilename() % test data funcDir = fullfile(outputDir, 'source', 'sub-ctrl002', 'ses-002', 'func'); eyetrackerDir = fullfile(outputDir, 'source', 'sub-ctrl002', 'ses-002', 'eyetracker'); - baseFilename = 'sub-ctrl002_ses-002_task-testtask'; - eventFilename = ['sub-ctrl002_ses-002_task-testtask_run-002_events_date-' ... + baseFilename = 'sub-ctrl002_ses-002_task-testTask'; + eventFilename = ['sub-ctrl002_ses-002_task-testTask_run-002_events_date-' ... cfg.fileName.date '.tsv']; - eyetrackerFilename = ['sub-ctrl002_ses-002_task-testtask_run-002_eyetrack_date-' ... + eyetrackerFilename = ['sub-ctrl002_ses-002_task-testTask_run-002_eyetrack_date-' ... cfg.fileName.date '.edf']; % make sure the func dir is created @@ -93,7 +93,7 @@ function test_createFilename() cfg.subject.subjectNb = 3; cfg.subject.sessionNb = 1; cfg.subject.runNb = 1; - cfg.task.name = 'testtask'; + cfg.task.name = 'testTask'; cfg.dir.output = outputDir; cfg.testingDevice = 'eeg'; From 4c53ec24bac99fee85edea75d92b8b6ef5ea4548 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Wed, 29 Jul 2020 13:11:44 +0200 Subject: [PATCH 22/22] mh autofix --- checkCFG.m | 8 ++++---- createFilename.m | 8 ++++---- subfun/createTaskName.m | 7 +++---- subfun/transferInfoToBids.m | 8 ++++---- tests/test_checkCFG.m | 6 +++--- tests/test_createFilename.m | 4 ++-- tests/test_createTaskName.m | 33 +++++++++++++++----------------- tests/test_transferInfoToBids.m | 34 ++++++++++++++++----------------- 8 files changed, 52 insertions(+), 56 deletions(-) diff --git a/checkCFG.m b/checkCFG.m index 9d6b93d8..e7c4d1dd 100644 --- a/checkCFG.m +++ b/checkCFG.m @@ -38,16 +38,16 @@ fieldsToSet = datasetDescriptionDefaults(fieldsToSet); fieldsToSet = mriJsonDefaults(fieldsToSet); fieldsToSet = megJsonDefaults(fieldsToSet); - + fieldsToSet = transferInfoToBids(fieldsToSet, cfg); - + cfg = setDefaultFields(cfg, fieldsToSet); end function fieldsToSet = mriDefaults(fieldsToSet) - % for file naming and JSON + % for file naming and JSON fieldsToSet.mri.contrastEnhancement = []; fieldsToSet.mri.phaseEncodingDirection = []; fieldsToSet.mri.reconstruction = []; @@ -185,4 +185,4 @@ fieldsToSet.bids.meg = orderfields(fieldsToSet.bids.meg); -end \ No newline at end of file +end diff --git a/createFilename.m b/createFilename.m index 733ffeb1..08d4391f 100644 --- a/createFilename.m +++ b/createFilename.m @@ -102,10 +102,10 @@ % set values for the suffixes for the different fields in the BIDS name fields2Check = { ... 'contrastEnhancement', ... - 'phaseEncodingDirection', ... % For BIDS file naming: phase encoding direction of acquisition for fMRI - 'reconstruction', ... % For BIDS file naming: reconstruction of fMRI images - 'echo', ... % For BIDS file naming: echo fMRI images - 'acquisition' % For BIDS file naming: acquisition of fMRI images + 'phaseEncodingDirection', ... + 'reconstruction', ... + 'echo', ... + 'acquisition' }; for iField = 1:numel(fields2Check) diff --git a/subfun/createTaskName.m b/subfun/createTaskName.m index 754bf262..6b3fd62b 100644 --- a/subfun/createTaskName.m +++ b/subfun/createTaskName.m @@ -4,15 +4,14 @@ % Name of the task (for resting state use the "rest" prefix). No two tasks % should have the same name. Task label is derived from this field by % removing all non alphanumeric ([a-zA-Z0-9]) characters. - + % camel case: upper case for first letter for all words but the first one spaceIdx = regexp(taskName, '[a-zA-Z0-9]*', 'start'); taskName(spaceIdx(2:end)) = upper(taskName(spaceIdx(2:end))); - + % remove invalid characters [unvalidCharacters] = regexp(taskName, '[^a-zA-Z0-9]'); taskNameValid = taskName; taskNameValid(unvalidCharacters) = []; - -end +end diff --git a/subfun/transferInfoToBids.m b/subfun/transferInfoToBids.m index 4a408b56..7f239cf7 100644 --- a/subfun/transferInfoToBids.m +++ b/subfun/transferInfoToBids.m @@ -1,16 +1,16 @@ function fieldsToSet = transferInfoToBids(fieldsToSet, cfg) % transfer any info that might have been provided by the user to the % relevant field for its reuse for BIDS filenames or JSON later - + if isfield(cfg, 'task') && isfield(cfg.task, 'name') [taskName, taskNameValid] = createTaskName(cfg.task.name); fieldsToSet.fileName.task = taskNameValid; fieldsToSet.bids.meg.TaskName = taskName; fieldsToSet.bids.mri.TaskName = taskName; end - + if isfield(cfg, 'mri') && isfield(cfg.mri, 'repetitionTime') fieldsToSet.bids.mri.RepetitionTime = cfg.mri.repetitionTime; end - -end \ No newline at end of file + +end diff --git a/tests/test_checkCFG.m b/tests/test_checkCFG.m index 9be6f5af..8c2155ed 100644 --- a/tests/test_checkCFG.m +++ b/tests/test_checkCFG.m @@ -43,13 +43,13 @@ function test_checkCFG() expectedStructure.dir.output = outputDir; expectedStructure.task.name = 'test task'; - + expectedStructure.testingDevice = 'mri'; expectedStructure.mri.repetitionTime = 1.56; - + expectedStructure.fileName.task = 'testTask'; - + expectedStructure.bids.mri.RepetitionTime = 1.56; expectedStructure.bids.mri.TaskName = 'test Task'; diff --git a/tests/test_createFilename.m b/tests/test_createFilename.m index 641bd6e4..ebce891f 100644 --- a/tests/test_createFilename.m +++ b/tests/test_createFilename.m @@ -50,7 +50,7 @@ function test_createFilename() cfg.subject.subjectNb = 2; cfg.subject.sessionNb = 2; cfg.subject.runNb = 2; - cfg.task.name = 'testTask'; + cfg.task.name = 'test task'; cfg.dir.output = outputDir; cfg.eyeTracker.do = true; @@ -93,7 +93,7 @@ function test_createFilename() cfg.subject.subjectNb = 3; cfg.subject.sessionNb = 1; cfg.subject.runNb = 1; - cfg.task.name = 'testTask'; + cfg.task.name = 'test task'; cfg.dir.output = outputDir; cfg.testingDevice = 'eeg'; diff --git a/tests/test_createTaskName.m b/tests/test_createTaskName.m index 15bd44db..6f30fe35 100644 --- a/tests/test_createTaskName.m +++ b/tests/test_createTaskName.m @@ -1,28 +1,25 @@ function test_createTaskName() % - + taskName = '&|@#-_(§!{})[]ù%£+/=:;.?,\<> visual task'; - - [taskName, taskNameValid] = createTaskName(taskName) - + + [taskName, taskNameValid] = createTaskName(taskName); + [unvalidCharacters] = regexp(taskNameValid, '[^a-zA-Z0-9]'); - + assert(isempty(unvalidCharacters)); - - + taskName = ' 09 visual task'; - - [taskName, taskNameValid] = createTaskName(taskName) - + + [taskName, taskNameValid] = createTaskName(taskName); + [unvalidCharacters] = regexp(taskNameValid, '[^a-zA-Z0-9]'); - + assert(isempty(unvalidCharacters)); - - + taskName = 'foo bar'; - [taskName, taskNameValid] = createTaskName(taskName) - assert(isequal(taskName, 'foo Bar')) - assert(isequal(taskNameValid, 'fooBar')) - -end + [taskName, taskNameValid] = createTaskName(taskName); + assert(isequal(taskName, 'foo Bar')); + assert(isequal(taskNameValid, 'fooBar')); +end diff --git a/tests/test_transferInfoToBids.m b/tests/test_transferInfoToBids.m index 2f8c5164..5af1816f 100644 --- a/tests/test_transferInfoToBids.m +++ b/tests/test_transferInfoToBids.m @@ -1,35 +1,35 @@ function test_transferInfoToBids() - + %% cfg = struct(); fieldsToSet = struct(); cfg = transferInfoToBids(fieldsToSet, cfg); - + expectedStruct = struct(); - - assert(isequal(expectedStruct, fieldsToSet)) - + + assert(isequal(expectedStruct, fieldsToSet)); + %% cfg.task.name = 'foo bar'; - + fieldsToSet = transferInfoToBids(fieldsToSet, cfg); - + expectedStruct.fileName.task = 'fooBar'; expectedStruct.bids.meg.TaskName = 'foo Bar'; expectedStruct.bids.mri.TaskName = 'foo Bar'; - - assert(isequal(expectedStruct, fieldsToSet)) - + + assert(isequal(expectedStruct, fieldsToSet)); + %% - clear cfg fieldsToSet expectedStruct - + clear cfg fieldsToSet expectedStruct; + cfg.mri.repetitionTime = 1.56; - + fieldsToSet = struct(); fieldsToSet = transferInfoToBids(fieldsToSet, cfg); expectedStruct.bids.mri.RepetitionTime = 1.56; - - assert(isequal(expectedStruct, fieldsToSet)) - -end \ No newline at end of file + + assert(isequal(expectedStruct, fieldsToSet)); + +end