From ba02498b3adbc7e12a74e5c3fa9abdf971b24407 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Wed, 22 Jul 2020 20:07:22 +0200 Subject: [PATCH 01/26] add JSONio and bids-matlab submod --- .gitmodules | 8 ++++++++ lib/JSONio | 1 + lib/bids-matlab | 1 + 3 files changed, 10 insertions(+) create mode 100644 .gitmodules create mode 160000 lib/JSONio create mode 160000 lib/bids-matlab diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..f5e8e9b5 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,8 @@ +[submodule "lib/bids-matlab"] + path = lib/bids-matlab + url = https://github.com/bids-standard/bids-matlab.git + branch = master +[submodule "lib/JSONio"] + path = lib/JSONio + url = https://github.com/gllmflndn/JSONio.git + branch = master diff --git a/lib/JSONio b/lib/JSONio new file mode 160000 index 00000000..6c699a31 --- /dev/null +++ b/lib/JSONio @@ -0,0 +1 @@ +Subproject commit 6c699a315ac2c578864d8b740a061bff47b718bf diff --git a/lib/bids-matlab b/lib/bids-matlab new file mode 160000 index 00000000..71257b51 --- /dev/null +++ b/lib/bids-matlab @@ -0,0 +1 @@ +Subproject commit 71257b51986f5075bb903eb090fe28b9b6dc3ebf From 816ef9d4ca1fcae41c9897ef4c5d77c9161b0cd8 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Wed, 22 Jul 2020 20:09:15 +0200 Subject: [PATCH 02/26] update mh config --- miss_hit.cfg | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/miss_hit.cfg b/miss_hit.cfg index fce7fa45..f7065cfc 100644 --- a/miss_hit.cfg +++ b/miss_hit.cfg @@ -1,3 +1,4 @@ line_length: 100 regex_function_name: "[a-z]+(([A-Z]){1}[A-Za-z]+)*" -suppress_rule: "copyright_notice" \ No newline at end of file +suppress_rule: "copyright_notice" +exclude_dir: "lib" \ No newline at end of file From 568c05cf0ce231dbc09ae290cb61efcc37a3ff45 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 23 Jul 2020 00:01:31 +0200 Subject: [PATCH 03/26] create functions to generate JSON files --- .gitignore | 2 + checkCFG.m | 69 ++++++++++++++++++--------- checkCppBidsDependencies.m | 7 +++ createBoldJson.m | 17 +++++++ createDataDictionary.m | 33 +++++++++++++ createDatasetDescription.m | 13 +++++ createFilename.m | 9 ++-- dummyData/CHANGES | 3 ++ dummyData/README | 1 + dummyData/dummyData.nii.gz | 0 initializeExtraColumns.m | 23 +++++++++ returnNamesExtraColumns.m | 11 +++++ saveEventsFile.m | 20 -------- tests/test_createBoldJson.m | 32 +++++++++++++ tests/test_createDataDictionary.m | 32 +++++++++++++ tests/test_createDatasetDescription.m | 31 ++++++++++++ 16 files changed, 258 insertions(+), 45 deletions(-) create mode 100644 checkCppBidsDependencies.m create mode 100644 createBoldJson.m create mode 100644 createDataDictionary.m create mode 100644 createDatasetDescription.m create mode 100644 dummyData/CHANGES create mode 100644 dummyData/README create mode 100644 dummyData/dummyData.nii.gz create mode 100644 initializeExtraColumns.m create mode 100644 returnNamesExtraColumns.m create mode 100644 tests/test_createBoldJson.m create mode 100644 tests/test_createDataDictionary.m create mode 100644 tests/test_createDatasetDescription.m diff --git a/.gitignore b/.gitignore index 01c7fc5b..c1cac9ae 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ check_my_code_report.txt test_code_report.txt + +output/** diff --git a/checkCFG.m b/checkCFG.m index 6bc03e8f..ac2f3c84 100644 --- a/checkCFG.m +++ b/checkCFG.m @@ -1,6 +1,8 @@ function [cfg, expParameters] = checkCFG(cfg, expParameters) % check that we have all the fields that we need in the experiment parameters + checkCppBidsDependencies(); + %% set the expParameters defaults fieldsToSet.verbose = 0; @@ -14,29 +16,12 @@ fieldsToSet.askGrpSess = [true true]; % BIDS + fieldsToSet = datasetDescriptionDefaults(fieldsToSet); + fieldsToSet = mriDefaults(fieldsToSet); - % dataset description json - % required - fieldsToSet.bids.datasetDescription.json.Name = ''; - fieldsToSet.bids.datasetDescription.json.BIDSVersion = ''; - % recommended - fieldsToSet.bids.datasetDescription.json.License = ''; - fieldsToSet.bids.datasetDescription.json.Authors = {''}; - fieldsToSet.bids.datasetDescription.json.Acknowledgements = ''; - fieldsToSet.bids.datasetDescription.json.HowToAcknowledge = ''; - fieldsToSet.bids.datasetDescription.json.Funding = {''}; - fieldsToSet.bids.datasetDescription.json.ReferencesAndLinks = {''}; - fieldsToSet.bids.datasetDescription.json.DatasetDOI = ''; - - % mri - % for json - fieldsToSet.MRI.repetitionTime = []; - % 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 + if isfield(expParameters, 'task') + fieldsToSet.bids.MRI.TaskName = expParameters.task; + end expParameters = setDefaults(expParameters, fieldsToSet); @@ -48,6 +33,9 @@ cfg = setDefaults(cfg, fieldsToSet); + % sort fields alphabetically + cfg = orderfields(cfg); + end function structure = setDefaults(structure, fieldsToSet) @@ -73,3 +61,40 @@ structure.(fieldName) = value; end end + +function fieldsToSet = datasetDescriptionDefaults(fieldsToSet) + % required + fieldsToSet.bids.datasetDescription.json.Name = ''; + fieldsToSet.bids.datasetDescription.json.BIDSVersion = ''; + % recommended + fieldsToSet.bids.datasetDescription.json.License = ''; + fieldsToSet.bids.datasetDescription.json.Authors = {''}; + fieldsToSet.bids.datasetDescription.json.Acknowledgements = ''; + fieldsToSet.bids.datasetDescription.json.HowToAcknowledge = ''; + fieldsToSet.bids.datasetDescription.json.Funding = {''}; + fieldsToSet.bids.datasetDescription.json.ReferencesAndLinks = {''}; + fieldsToSet.bids.datasetDescription.json.DatasetDOI = ''; +end + +function fieldsToSet = mriDefaults(fieldsToSet) + + % for json for funcfional data + % required + fieldsToSet.bids.MRI.RepetitionTime = []; + fieldsToSet.bids.MRI.SliceTiming = ''; + fieldsToSet.bids.MRI.TaskName = ''; + fieldsToSet.bids.MRI.PhaseEncodingDirection = ''; + fieldsToSet.bids.MRI.EffectiveEchoSpacing = ''; + fieldsToSet.bids.MRI.EchoTime = ''; + % recommended + fieldsToSet.bids.MRI.Instructions = ''; + fieldsToSet.bids.MRI.TaskDescription = ''; + + % 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 + +end diff --git a/checkCppBidsDependencies.m b/checkCppBidsDependencies.m new file mode 100644 index 00000000..c9290587 --- /dev/null +++ b/checkCppBidsDependencies.m @@ -0,0 +1,7 @@ +function checkCppBidsDependencies + + pth = fileparts(mfilename('fullpath')); + addpath(fullfile(pth, 'lib', 'JSONio')); + addpath(fullfile(pth, 'lib', 'bids-matlab')); + +end diff --git a/createBoldJson.m b/createBoldJson.m new file mode 100644 index 00000000..fcb14059 --- /dev/null +++ b/createBoldJson.m @@ -0,0 +1,17 @@ +function createBoldJson(expParameters) + + opts.Indent = ' '; + + fileName = strrep(expParameters.fileName.events, '_events', '_bold'); + fileName = strrep(fileName, '.tsv', '.json'); + + fileName = fullfile( ... + expParameters.subjectOutputDir, ... + expParameters.modality, ... + fileName); + + jsonContent = expParameters.bids.MRI; + + bids.util.jsonencode(fileName, jsonContent, opts); + +end diff --git a/createDataDictionary.m b/createDataDictionary.m new file mode 100644 index 00000000..bb2c7648 --- /dev/null +++ b/createDataDictionary.m @@ -0,0 +1,33 @@ +function createDataDictionary(expParameters, logFile) + + opts.Indent = ' '; + + fileName = strrep(expParameters.fileName.events, '.tsv', '.json'); + + fileName = fullfile( ... + expParameters.subjectOutputDir, ... + expParameters.modality, ... + fileName); + + jsonContent = struct( ... + 'onset', struct( ... + 'Description', 'time elapsed since experiment start', ... + 'Unit', 's'), ... + 'trial_type', struct( ... + 'Description', 'types of trial', ... + 'Levels', ''), ... + 'duration', struct( ... + 'Description', 'duration of the event or the block', ... + 'Unit', 's') ... + ); + + % transfer content of extra fields to json content + namesExtraColumns = returnNamesExtraColumns(logFile); + for iExtraColumn = 1:numel(namesExtraColumns) + jsonContent.(namesExtraColumns{iExtraColumn}) = ... + logFile(1).extraColumns.(namesExtraColumns{iExtraColumn}); + end + + bids.util.jsonencode(fileName, jsonContent, opts); + +end diff --git a/createDatasetDescription.m b/createDatasetDescription.m new file mode 100644 index 00000000..5772703a --- /dev/null +++ b/createDatasetDescription.m @@ -0,0 +1,13 @@ +function createDatasetDescription(expParameters) + + opts.Indent = ' '; + + fileName = fullfile( ... + expParameters.outputDir, ... + 'dataset_description.json'); + + jsonContent = expParameters.bids.datasetDescription; + + bids.util.jsonencode(fileName, jsonContent, opts); + +end diff --git a/createFilename.m b/createFilename.m index 0135ad9e..d48d21f4 100644 --- a/createFilename.m +++ b/createFilename.m @@ -38,6 +38,7 @@ end function expParameters = getModality(cfg, expParameters) + switch lower(cfg.testingDevice) case 'pc' modality = 'beh'; @@ -54,14 +55,16 @@ end expParameters.modality = modality; + end -function [subjectGrp, subjectNb, sessionNb, modality] = extractInput(expParameters) +function [subjectGrp, subjectNb, sessionNb, modality, taskName] = extractInput(expParameters) subjectGrp = expParameters.subjectGrp; subjectNb = expParameters.subjectNb; sessionNb = expParameters.sessionNb; modality = expParameters.modality; + taskName = expParameters.task; if isempty(sessionNb) sessionNb = 1; @@ -119,7 +122,7 @@ function expParameters = setFilenames(cfg, expParameters) - [subjectGrp, subjectNb, sessionNb, modality] = extractInput(expParameters); + [subjectGrp, subjectNb, sessionNb, modality, taskName] = extractInput(expParameters); runSuffix = expParameters.runSuffix; pattern = expParameters.pattern; @@ -137,7 +140,7 @@ fileNameBase = ... ['sub-', subjectGrp, sprintf(pattern, subjectNb), ... '_ses-', sprintf(pattern, sessionNb), ... - '_task-', expParameters.task]; + '_task-', taskName]; expParameters.fileName.base = fileNameBase; switch modality diff --git a/dummyData/CHANGES b/dummyData/CHANGES new file mode 100644 index 00000000..12eb6c37 --- /dev/null +++ b/dummyData/CHANGES @@ -0,0 +1,3 @@ +1.0.0 YYYY-MM-DD + + - initial release \ No newline at end of file diff --git a/dummyData/README b/dummyData/README new file mode 100644 index 00000000..52da2380 --- /dev/null +++ b/dummyData/README @@ -0,0 +1 @@ +# README \ No newline at end of file diff --git a/dummyData/dummyData.nii.gz b/dummyData/dummyData.nii.gz new file mode 100644 index 00000000..e69de29b diff --git a/initializeExtraColumns.m b/initializeExtraColumns.m new file mode 100644 index 00000000..634c89cf --- /dev/null +++ b/initializeExtraColumns.m @@ -0,0 +1,23 @@ +function logFile = initializeExtraColumns(logFile) + % initialize the fields for the extra columns + % USAGE + % logfile.extraColumns{'Speed', 'Response key'} + % logFile = initializeExtraColumns(logFile) + + % convert the cell of column name into a structure + if iscell(logFile(1).extraColumns) + tmp = struct(); + for iExtraColumn = 1:numel(logFile(1).extraColumns) + extraColumnName = logFile(1).extraColumns{iExtraColumn}; + tmp.(extraColumnName) = struct( ... + 'length', 1, ... + 'LongName', '', ..., + 'Description', '', ... + 'Levels', '', ... + 'Units', '', ... + 'TermURL', ''); + end + logFile(1).extraColumns = tmp; + end + +end diff --git a/returnNamesExtraColumns.m b/returnNamesExtraColumns.m new file mode 100644 index 00000000..3a220ea3 --- /dev/null +++ b/returnNamesExtraColumns.m @@ -0,0 +1,11 @@ +function [namesExtraColumns, logFile] = returnNamesExtraColumns(logFile) + + namesExtraColumns = []; + + logFile = initializeExtraColumns(logFile); + + if isfield(logFile, 'extraColumns') && ~isempty(logFile(1).extraColumns) + namesExtraColumns = fieldnames(logFile(1).extraColumns); + end + +end diff --git a/saveEventsFile.m b/saveEventsFile.m index 98f14ee8..e85f2951 100644 --- a/saveEventsFile.m +++ b/saveEventsFile.m @@ -168,26 +168,6 @@ end -function [namesExtraColumns, logFile] = returnNamesExtraColumns(logFile) - - namesExtraColumns = []; - - % convert the cell of column name into a structure - if iscell(logFile(1).extraColumns) - tmp = struct(); - for iExtraColumn = 1:numel(logFile(1).extraColumns) - extraColumnName = logFile(1).extraColumns{iExtraColumn}; - tmp.(extraColumnName) = struct('length', 1); - end - logFile(1).extraColumns = tmp; - end - - if isfield(logFile, 'extraColumns') && ~isempty(logFile(1).extraColumns) - namesExtraColumns = fieldnames(logFile(1).extraColumns); - end - -end - function logFile = printHeaderExtraColumns(logFile) % print any extra column specified by the user diff --git a/tests/test_createBoldJson.m b/tests/test_createBoldJson.m new file mode 100644 index 00000000..907acd86 --- /dev/null +++ b/tests/test_createBoldJson.m @@ -0,0 +1,32 @@ +function test_createBoldJson() + + fprintf('\n\n--------------------------------------------------------------------\n\n'); + + outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); + + %%% set up part + + expParameters.subjectNb = 1; + expParameters.runNb = 1; + expParameters.task = 'testtask'; + expParameters.outputDir = outputDir; + + cfg = struct(); + cfg.testingDevice = 'mri'; + + [cfg, expParameters] = createFilename(cfg, expParameters); %#ok + logFile = saveEventsFile('open', expParameters); + + createBoldJson(expParameters); + + %%% 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']; + + % check that the file has the right path and name + assert(exist(fullfile(funcDir, eventFilename), 'file') == 2); + +end diff --git a/tests/test_createDataDictionary.m b/tests/test_createDataDictionary.m new file mode 100644 index 00000000..50768795 --- /dev/null +++ b/tests/test_createDataDictionary.m @@ -0,0 +1,32 @@ +function test_createDataDictionary() + + fprintf('\n\n--------------------------------------------------------------------\n\n'); + + outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); + + %%% set up part + + expParameters.subjectNb = 1; + expParameters.runNb = 1; + expParameters.task = 'testtask'; + expParameters.outputDir = outputDir; + + cfg = struct(); + cfg.testingDevice = 'mri'; + + [cfg, expParameters] = createFilename(cfg, expParameters); + logFile = saveEventsFile('open', expParameters); + + createDataDictionary(expParameters, logFile); + + %%% test part + + % test data + funcDir = fullfile(outputDir, 'source', 'sub-001', 'ses-001', 'func'); + eventFilename = ['sub-001_ses-001_task-testtask_run-001_events_date-' ... + expParameters.date '.json']; + + % check that the file has the right path and name + assert(exist(fullfile(funcDir, eventFilename), 'file') == 2); + +end diff --git a/tests/test_createDatasetDescription.m b/tests/test_createDatasetDescription.m new file mode 100644 index 00000000..1aee9a10 --- /dev/null +++ b/tests/test_createDatasetDescription.m @@ -0,0 +1,31 @@ +function test_createDatasetDescription() + + fprintf('\n\n--------------------------------------------------------------------\n\n'); + + outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output', 'source'); + + %%% set up part + + expParameters.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 = struct(); + + [cfg, expParameters] = checkCFG(cfg, expParameters); %#ok<*ASGLU> + + createDatasetDescription(expParameters); + + %%% test part + + % test data + directory = fullfile(outputDir); + filename = 'dataset_description.json'; + + % check that the file has the right path and name + assert(exist(fullfile(directory, filename), 'file') == 2); + +end From 4be108994248f447df1ea6271088ba0c936bf732 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 23 Jul 2020 09:55:41 +0200 Subject: [PATCH 04/26] refactor subfunctions --- checkCFG.m | 28 +--------- initializeExtraColumns.m | 31 ++++++++--- returnHeaderName.m | 7 +++ returnNamesExtraColumns.m | 2 - returnNbColumns.m | 10 ++++ saveEventsFile.m | 27 ++------- setDefaultFields.m | 23 ++++++++ tests/test_initializeExtraColumns.m | 64 ++++++++++++++++++++++ tests/test_saveEventsFileOpenMultiColumn.m | 6 +- 9 files changed, 139 insertions(+), 59 deletions(-) create mode 100644 returnHeaderName.m create mode 100644 returnNbColumns.m create mode 100644 setDefaultFields.m create mode 100644 tests/test_initializeExtraColumns.m diff --git a/checkCFG.m b/checkCFG.m index ac2f3c84..6ad2127e 100644 --- a/checkCFG.m +++ b/checkCFG.m @@ -23,7 +23,7 @@ fieldsToSet.bids.MRI.TaskName = expParameters.task; end - expParameters = setDefaults(expParameters, fieldsToSet); + expParameters = setDefaultFields(expParameters, fieldsToSet); %% set the cfg defaults @@ -31,37 +31,13 @@ fieldsToSet.testingDevice = 'pc'; fieldsToSet.eyeTracker = false; - cfg = setDefaults(cfg, fieldsToSet); + cfg = setDefaultFields(cfg, fieldsToSet); % sort fields alphabetically cfg = orderfields(cfg); end -function structure = setDefaults(structure, fieldsToSet) - % loop through the defaults fiels to set and update if they don't exist - - names = fieldnames(fieldsToSet); - - for i = 1:numel(names) - - thisField = fieldsToSet.(names{i}); - - structure = setFieldToIfNotPresent( ... - structure, ... - names{i}, ... - thisField); - - end - -end - -function structure = setFieldToIfNotPresent(structure, fieldName, value) - if ~isfield(structure, fieldName) - structure.(fieldName) = value; - end -end - function fieldsToSet = datasetDescriptionDefaults(fieldsToSet) % required fieldsToSet.bids.datasetDescription.json.Name = ''; diff --git a/initializeExtraColumns.m b/initializeExtraColumns.m index 634c89cf..5df181cd 100644 --- a/initializeExtraColumns.m +++ b/initializeExtraColumns.m @@ -4,20 +4,37 @@ % logfile.extraColumns{'Speed', 'Response key'} % logFile = initializeExtraColumns(logFile) + fieldsToSet.length = 1; + fieldsToSet.bids.LongName = ''; + fieldsToSet.bids.Description = ''; + fieldsToSet.bids.Levels = ''; + fieldsToSet.bids.TermURL = ''; + % convert the cell of column name into a structure if iscell(logFile(1).extraColumns) + + nbExtraColumns = numel(logFile(1).extraColumns); tmp = struct(); - for iExtraColumn = 1:numel(logFile(1).extraColumns) + + for iExtraColumn = 1:nbExtraColumns extraColumnName = logFile(1).extraColumns{iExtraColumn}; tmp.(extraColumnName) = struct( ... - 'length', 1, ... - 'LongName', '', ..., - 'Description', '', ... - 'Levels', '', ... - 'Units', '', ... - 'TermURL', ''); + 'length', 1); + tmp.(extraColumnName) = setDefaultFields(tmp.(extraColumnName), fieldsToSet); end + logFile(1).extraColumns = tmp; + + end + + [namesExtraColumns] = returnNamesExtraColumns(logFile); + for iExtraColumn = 1:numel(namesExtraColumns) + + logFile(1).extraColumns.(namesExtraColumns{iExtraColumn}) = ... + setDefaultFields( ... + logFile(1).extraColumns.(namesExtraColumns{iExtraColumn}), ... + fieldsToSet); + end end diff --git a/returnHeaderName.m b/returnHeaderName.m new file mode 100644 index 00000000..05902dfd --- /dev/null +++ b/returnHeaderName.m @@ -0,0 +1,7 @@ +function headerName = returnHeaderName(columnName, nbCol, iCol) + if nbCol == 1 + headerName = sprintf('%s', columnName); + else + headerName = sprintf('%s_%02.0f', columnName, iCol); + end +end diff --git a/returnNamesExtraColumns.m b/returnNamesExtraColumns.m index 3a220ea3..c1a204e1 100644 --- a/returnNamesExtraColumns.m +++ b/returnNamesExtraColumns.m @@ -2,8 +2,6 @@ namesExtraColumns = []; - logFile = initializeExtraColumns(logFile); - if isfield(logFile, 'extraColumns') && ~isempty(logFile(1).extraColumns) namesExtraColumns = fieldnames(logFile(1).extraColumns); end diff --git a/returnNbColumns.m b/returnNbColumns.m new file mode 100644 index 00000000..a3121229 --- /dev/null +++ b/returnNbColumns.m @@ -0,0 +1,10 @@ +function nbCol = returnNbColumns(logFile, nameExtraColumn) + + thisExtraColumn = logFile(1).extraColumns.(nameExtraColumn); + + nbCol = 1; + + if isfield(thisExtraColumn, 'length') + nbCol = thisExtraColumn.length; + end +end diff --git a/saveEventsFile.m b/saveEventsFile.m index e85f2951..f65503e0 100644 --- a/saveEventsFile.m +++ b/saveEventsFile.m @@ -54,12 +54,16 @@ case 'open' + logFile = initializeExtraColumns(logFile); + logFile.filename = expParameters.fileName.events; logFile = initializeFile(expParameters, logFile); case 'open_stim' + logFile = initializeExtraColumns(logFile); + logFile.filename = expParameters.fileName.stim; logFile = initializeFile(expParameters, logFile); @@ -177,17 +181,9 @@ nbCol = returnNbColumns(logFile, namesExtraColumns{iExtraColumn}); - if ~isfield(logFile(1).extraColumns.(namesExtraColumns{iExtraColumn}), 'length') - logFile(1).extraColumns.(namesExtraColumns{iExtraColumn}).length = nbCol; - end - - for iColNb = 1:nbCol + for iCol = 1:nbCol - if nbCol == 1 - headerName = sprintf('%s', namesExtraColumns{iExtraColumn}); - else - headerName = sprintf('%s-%02.0f', namesExtraColumns{iExtraColumn}, iColNb); - end + headerName = returnHeaderName(namesExtraColumns{iExtraColumn}, nbCol, iCol); fprintf(logFile.fileID, '%s\t', headerName); @@ -197,17 +193,6 @@ end -function nbCol = returnNbColumns(logFile, nameExtraColumn) - - thisExtraColumn = logFile(1).extraColumns.(nameExtraColumn); - - nbCol = 1; - - if isfield(thisExtraColumn, 'length') - nbCol = thisExtraColumn.length; - end -end - function data = checkInput(data, expectedLength) % check the data to write % default will be 'NA' for chars and NaN for numeric data diff --git a/setDefaultFields.m b/setDefaultFields.m new file mode 100644 index 00000000..75669017 --- /dev/null +++ b/setDefaultFields.m @@ -0,0 +1,23 @@ +function structure = setDefaultFields(structure, fieldsToSet) + % loop through the defaults fiels to set and update if they don't exist + + names = fieldnames(fieldsToSet); + + for i = 1:numel(names) + + thisField = fieldsToSet.(names{i}); + + structure = setFieldToIfNotPresent( ... + structure, ... + names{i}, ... + thisField); + + end + +end + +function structure = setFieldToIfNotPresent(structure, fieldName, value) + if ~isfield(structure, fieldName) + structure.(fieldName) = value; + end +end diff --git a/tests/test_initializeExtraColumns.m b/tests/test_initializeExtraColumns.m new file mode 100644 index 00000000..f65d8cd3 --- /dev/null +++ b/tests/test_initializeExtraColumns.m @@ -0,0 +1,64 @@ +function test_initializeExtraColumns() + + fprintf('\n\n--------------------------------------------------------------------\n\n'); + + clear; + + %%% set up + logFile = struct('filename', [], 'extraColumns', cell(1)); + logFile(1).filename = ''; + + %%% do stuff + logFile = initializeExtraColumns(logFile); + + %%% test section + expectedStrcut(1).filename = ''; + expectedStrcut(1).extraColumns = []; + + assert(isequal(expectedStrcut, logFile)); + + fprintf('\n\n--------------------------------------------------------------------\n\n'); + + clear; + + %%% set up + logFile.extraColumns = {'Speed'}; + + %%% do stuff + logFile = initializeExtraColumns(logFile); + + %%% test section + expectedStrcut(1).extraColumns.Speed.length = 1; + expectedStrcut(1).extraColumns.Speed.bids.LongName = ''; + expectedStrcut(1).extraColumns.Speed.bids.Description = ''; + expectedStrcut(1).extraColumns.Speed.bids.Levels = ''; + expectedStrcut(1).extraColumns.Speed.bids.TermURL = ''; + + assert(isequal(expectedStrcut, logFile)); + + fprintf('\n\n--------------------------------------------------------------------\n\n'); + + clear; + + %%% set up + logFile.extraColumns.Speed.length = 1; + logFile.extraColumns.LHL24.length = 3; + + %%% do stuff + logFile = initializeExtraColumns(logFile); + + %%% test section + expectedStrcut(1).extraColumns.Speed.length = 1; + expectedStrcut(1).extraColumns.Speed.bids.LongName = ''; + expectedStrcut(1).extraColumns.Speed.bids.Description = ''; + expectedStrcut(1).extraColumns.Speed.bids.Levels = ''; + expectedStrcut(1).extraColumns.Speed.bids.TermURL = ''; + expectedStrcut(1).extraColumns.LHL24.length = 3; + expectedStrcut(1).extraColumns.LHL24.bids.LongName = ''; + expectedStrcut(1).extraColumns.LHL24.bids.Description = ''; + expectedStrcut(1).extraColumns.LHL24.bids.Levels = ''; + expectedStrcut(1).extraColumns.LHL24.bids.TermURL = ''; + + assert(isequal(expectedStrcut, logFile)); + +end diff --git a/tests/test_saveEventsFileOpenMultiColumn.m b/tests/test_saveEventsFileOpenMultiColumn.m index 4ff7e64a..ee3fd117 100644 --- a/tests/test_saveEventsFileOpenMultiColumn.m +++ b/tests/test_saveEventsFileOpenMultiColumn.m @@ -16,7 +16,7 @@ function test_saveEventsFileOpenMultiColumn() cfg.testingDevice = 'mri'; - [cfg, expParameters] = createFilename(cfg, expParameters); + [cfg, expParameters] = createFilename(cfg, expParameters); %#ok % define the extra columns: here we specify how many columns we want for % each variable @@ -48,8 +48,8 @@ function test_saveEventsFileOpenMultiColumn() % 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{5}{1}, 'LHL24_01')); + assert(isequal(C{16}{1}, 'LHL24_12')); assert(isequal(C{17}{1}, 'is_Fixation')); end From 2bf55e9264cff0a3a927e1704ab4c433de5ced25 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 23 Jul 2020 10:22:59 +0200 Subject: [PATCH 05/26] move functions to subfun folder --- initializeExtraColumns.m => subfun/initializeExtraColumns.m | 0 returnHeaderName.m => subfun/returnHeaderName.m | 0 returnNamesExtraColumns.m => subfun/returnNamesExtraColumns.m | 0 returnNbColumns.m => subfun/returnNbColumns.m | 0 setDefaultFields.m => subfun/setDefaultFields.m | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename initializeExtraColumns.m => subfun/initializeExtraColumns.m (100%) rename returnHeaderName.m => subfun/returnHeaderName.m (100%) rename returnNamesExtraColumns.m => subfun/returnNamesExtraColumns.m (100%) rename returnNbColumns.m => subfun/returnNbColumns.m (100%) rename setDefaultFields.m => subfun/setDefaultFields.m (100%) diff --git a/initializeExtraColumns.m b/subfun/initializeExtraColumns.m similarity index 100% rename from initializeExtraColumns.m rename to subfun/initializeExtraColumns.m diff --git a/returnHeaderName.m b/subfun/returnHeaderName.m similarity index 100% rename from returnHeaderName.m rename to subfun/returnHeaderName.m diff --git a/returnNamesExtraColumns.m b/subfun/returnNamesExtraColumns.m similarity index 100% rename from returnNamesExtraColumns.m rename to subfun/returnNamesExtraColumns.m diff --git a/returnNbColumns.m b/subfun/returnNbColumns.m similarity index 100% rename from returnNbColumns.m rename to subfun/returnNbColumns.m diff --git a/setDefaultFields.m b/subfun/setDefaultFields.m similarity index 100% rename from setDefaultFields.m rename to subfun/setDefaultFields.m From 9458064fa1738f824f6a302774f4f152635514bd Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 23 Jul 2020 10:24:19 +0200 Subject: [PATCH 06/26] update tests --- checkCppBidsDependencies.m | 1 + createDataDictionary.m | 15 ++++++++-- createDatasetDescription.m | 2 +- tests/testData/eventsDataDictionary.json | 38 ++++++++++++++++++++++++ tests/test_createBoldJson.m | 5 ++-- tests/test_createDataDictionary.m | 19 +++++++++--- tests/test_createDatasetDescription.m | 2 +- tests/test_initializeExtraColumns.m | 3 ++ 8 files changed, 75 insertions(+), 10 deletions(-) create mode 100644 tests/testData/eventsDataDictionary.json diff --git a/checkCppBidsDependencies.m b/checkCppBidsDependencies.m index c9290587..46695a52 100644 --- a/checkCppBidsDependencies.m +++ b/checkCppBidsDependencies.m @@ -3,5 +3,6 @@ pth = fileparts(mfilename('fullpath')); addpath(fullfile(pth, 'lib', 'JSONio')); addpath(fullfile(pth, 'lib', 'bids-matlab')); + addpath(fullfile(pth, 'subfun')); end diff --git a/createDataDictionary.m b/createDataDictionary.m index bb2c7648..828e3918 100644 --- a/createDataDictionary.m +++ b/createDataDictionary.m @@ -23,9 +23,20 @@ function createDataDictionary(expParameters, logFile) % transfer content of extra fields to json content namesExtraColumns = returnNamesExtraColumns(logFile); + for iExtraColumn = 1:numel(namesExtraColumns) - jsonContent.(namesExtraColumns{iExtraColumn}) = ... - logFile(1).extraColumns.(namesExtraColumns{iExtraColumn}); + + nbCol = returnNbColumns(logFile, namesExtraColumns{iExtraColumn}); + + for iCol = 1:nbCol + + headerName = returnHeaderName(namesExtraColumns{iExtraColumn}, nbCol, iCol); + + jsonContent.(headerName) = ... + logFile(1).extraColumns.(namesExtraColumns{iExtraColumn}).bids; + + end + end bids.util.jsonencode(fileName, jsonContent, opts); diff --git a/createDatasetDescription.m b/createDatasetDescription.m index 5772703a..4e1cbb8f 100644 --- a/createDatasetDescription.m +++ b/createDatasetDescription.m @@ -3,7 +3,7 @@ function createDatasetDescription(expParameters) opts.Indent = ' '; fileName = fullfile( ... - expParameters.outputDir, ... + expParameters.outputDir, 'source', ... 'dataset_description.json'); jsonContent = expParameters.bids.datasetDescription; diff --git a/tests/testData/eventsDataDictionary.json b/tests/testData/eventsDataDictionary.json new file mode 100644 index 00000000..45570965 --- /dev/null +++ b/tests/testData/eventsDataDictionary.json @@ -0,0 +1,38 @@ +{ + "onset": { + "Description": "time elapsed since experiment start", + "Unit": "s" + }, + "trial_type": { + "Description": "types of trial", + "Levels": "" + }, + "duration": { + "Description": "duration of the event or the block", + "Unit": "s" + }, + "Speed": { + "LongName": "", + "Description": "", + "Levels": "", + "TermURL": "" + }, + "LHL24_01": { + "LongName": "", + "Description": "", + "Levels": "", + "TermURL": "" + }, + "LHL24_02": { + "LongName": "", + "Description": "", + "Levels": "", + "TermURL": "" + }, + "LHL24_03": { + "LongName": "", + "Description": "", + "Levels": "", + "TermURL": "" + } +} \ No newline at end of file diff --git a/tests/test_createBoldJson.m b/tests/test_createBoldJson.m index 907acd86..91bb3957 100644 --- a/tests/test_createBoldJson.m +++ b/tests/test_createBoldJson.m @@ -14,8 +14,9 @@ function test_createBoldJson() cfg = struct(); cfg.testingDevice = 'mri'; - [cfg, expParameters] = createFilename(cfg, expParameters); %#ok - logFile = saveEventsFile('open', expParameters); + [cfg, expParameters] = createFilename(cfg, expParameters); %#ok<*ASGLU> + + logFile = saveEventsFile('open', expParameters); %#ok<*NASGU> createBoldJson(expParameters); diff --git a/tests/test_createDataDictionary.m b/tests/test_createDataDictionary.m index 50768795..130d99b1 100644 --- a/tests/test_createDataDictionary.m +++ b/tests/test_createDataDictionary.m @@ -2,6 +2,8 @@ function test_createDataDictionary() fprintf('\n\n--------------------------------------------------------------------\n\n'); + clear; + outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); %%% set up part @@ -14,8 +16,11 @@ function test_createDataDictionary() cfg = struct(); cfg.testingDevice = 'mri'; - [cfg, expParameters] = createFilename(cfg, expParameters); - logFile = saveEventsFile('open', expParameters); + [cfg, expParameters] = createFilename(cfg, expParameters); %#ok + + logFile.extraColumns.Speed.length = 1; + logFile.extraColumns.LHL24.length = 3; + logFile = saveEventsFile('open', expParameters, logFile); createDataDictionary(expParameters, logFile); @@ -23,10 +28,16 @@ function test_createDataDictionary() % test data funcDir = fullfile(outputDir, 'source', 'sub-001', 'ses-001', 'func'); - eventFilename = ['sub-001_ses-001_task-testtask_run-001_events_date-' ... + jsonFilename = ['sub-001_ses-001_task-testtask_run-001_events_date-' ... expParameters.date '.json']; % check that the file has the right path and name - assert(exist(fullfile(funcDir, eventFilename), 'file') == 2); + assert(exist(fullfile(funcDir, jsonFilename), 'file') == 2); + + % check content + expectedStruct = bids.util.jsondecode(fullfile(pwd, 'testData', 'eventsDataDictionary.json')); + actualStruct = bids.util.jsondecode(fullfile(funcDir, jsonFilename)); + + assert(isequal(expectedStruct, actualStruct)); end diff --git a/tests/test_createDatasetDescription.m b/tests/test_createDatasetDescription.m index 1aee9a10..dca6034b 100644 --- a/tests/test_createDatasetDescription.m +++ b/tests/test_createDatasetDescription.m @@ -2,7 +2,7 @@ function test_createDatasetDescription() fprintf('\n\n--------------------------------------------------------------------\n\n'); - outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output', 'source'); + outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); %%% set up part diff --git a/tests/test_initializeExtraColumns.m b/tests/test_initializeExtraColumns.m index f65d8cd3..2de1bbe6 100644 --- a/tests/test_initializeExtraColumns.m +++ b/tests/test_initializeExtraColumns.m @@ -5,6 +5,7 @@ function test_initializeExtraColumns() clear; %%% set up + checkCppBidsDependencies() logFile = struct('filename', [], 'extraColumns', cell(1)); logFile(1).filename = ''; @@ -22,6 +23,7 @@ function test_initializeExtraColumns() clear; %%% set up + checkCppBidsDependencies() logFile.extraColumns = {'Speed'}; %%% do stuff @@ -41,6 +43,7 @@ function test_initializeExtraColumns() clear; %%% set up + checkCppBidsDependencies() logFile.extraColumns.Speed.length = 1; logFile.extraColumns.LHL24.length = 3; From 99299fc694862b1012035a38ad20966c8bb10fe0 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 23 Jul 2020 10:47:10 +0200 Subject: [PATCH 07/26] use dynamic field in createFilename --- createFilename.m | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/createFilename.m b/createFilename.m index d48d21f4..f3c6a944 100644 --- a/createFilename.m +++ b/createFilename.m @@ -109,12 +109,11 @@ }; for iField = 1:numel(fields2Check) - if isempty (getfield(expParameters.MRI, fields2Check{iField})) %#ok<*GFLD> - expParameters.MRI = setfield(expParameters.MRI, [fields2Check{iField} 'Suffix'], ... - ''); %#ok<*SFLD> + if isempty (expParameters.MRI.(fields2Check{iField})) %#ok<*GFLD> + expParameters.MRI.([fields2Check{iField} 'Suffix']) = ''; %#ok<*SFLD> else - expParameters.MRI = setfield(expParameters.MRI, [fields2Check{iField} 'Suffix'], ... - ['_' fields2Check{iField} '-' getfield(expParameters.MRI, fields2Check{iField})]); + expParameters.MRI.([fields2Check{iField} 'Suffix']) = ... + ['_' fields2Check{iField} '-' getfield(expParameters.MRI, fields2Check{iField})]; end end From 3c33ab5e9f15d1fd33ee5537a6d4273dc70c1fb3 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 23 Jul 2020 10:47:31 +0200 Subject: [PATCH 08/26] minor fixes --- checkCFG.m | 2 +- tests/test_createDatasetDescription.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/checkCFG.m b/checkCFG.m index 6ad2127e..85c31527 100644 --- a/checkCFG.m +++ b/checkCFG.m @@ -11,7 +11,7 @@ '..', ... 'output'); - fieldsToSet.subjectGrp = []; % in case no group was provided + fieldsToSet.subjectGrp = ''; % in case no group was provided fieldsToSet.sessionNb = 1; % in case no session was provided fieldsToSet.askGrpSess = [true true]; diff --git a/tests/test_createDatasetDescription.m b/tests/test_createDatasetDescription.m index dca6034b..f5fdbefe 100644 --- a/tests/test_createDatasetDescription.m +++ b/tests/test_createDatasetDescription.m @@ -22,7 +22,7 @@ function test_createDatasetDescription() %%% test part % test data - directory = fullfile(outputDir); + directory = fullfile(outputDir, 'source'); filename = 'dataset_description.json'; % check that the file has the right path and name From 7bbc271f55dfe4c6cc306e69da309054ff8d3059 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 23 Jul 2020 10:48:28 +0200 Subject: [PATCH 09/26] mh autofix --- tests/test_initializeExtraColumns.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_initializeExtraColumns.m b/tests/test_initializeExtraColumns.m index 2de1bbe6..694ce2f6 100644 --- a/tests/test_initializeExtraColumns.m +++ b/tests/test_initializeExtraColumns.m @@ -5,7 +5,7 @@ function test_initializeExtraColumns() clear; %%% set up - checkCppBidsDependencies() + checkCppBidsDependencies(); logFile = struct('filename', [], 'extraColumns', cell(1)); logFile(1).filename = ''; @@ -23,7 +23,7 @@ function test_initializeExtraColumns() clear; %%% set up - checkCppBidsDependencies() + checkCppBidsDependencies(); logFile.extraColumns = {'Speed'}; %%% do stuff @@ -43,7 +43,7 @@ function test_initializeExtraColumns() clear; %%% set up - checkCppBidsDependencies() + checkCppBidsDependencies(); logFile.extraColumns.Speed.length = 1; logFile.extraColumns.LHL24.length = 3; From 7ec63b31defea8d069cf703e611fb48bd7d1e4c1 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 23 Jul 2020 11:21:33 +0200 Subject: [PATCH 10/26] boldFilename --- checkCppBidsDependencies.m | 1 + lib/utils/file_utils.m | 233 +++++++++++++++++++++++++++++++++++++ lib/utils/parse_filename.m | 56 +++++++++ 3 files changed, 290 insertions(+) create mode 100644 lib/utils/file_utils.m create mode 100644 lib/utils/parse_filename.m diff --git a/checkCppBidsDependencies.m b/checkCppBidsDependencies.m index 46695a52..dc878448 100644 --- a/checkCppBidsDependencies.m +++ b/checkCppBidsDependencies.m @@ -3,6 +3,7 @@ pth = fileparts(mfilename('fullpath')); addpath(fullfile(pth, 'lib', 'JSONio')); addpath(fullfile(pth, 'lib', 'bids-matlab')); + addpath(fullfile(pth, 'lib', 'utils')); addpath(fullfile(pth, 'subfun')); end diff --git a/lib/utils/file_utils.m b/lib/utils/file_utils.m new file mode 100644 index 00000000..91385d1c --- /dev/null +++ b/lib/utils/file_utils.m @@ -0,0 +1,233 @@ +function varargout = file_utils(str,varargin) +% Character array (or cell array of strings) handling facility +% FORMAT str = file_utils(str,option) +% str - character array, or cell array of strings +% option - string of requested item - one among: +% {'path', 'basename', 'ext', 'filename', 'cpath', 'fpath'} +% +% FORMAT str = file_utils(str,opt_key,opt_val,...) +% str - character array, or cell array of strings +% opt_key - string of targeted item - one among: +% {'path', 'basename', 'ext', 'filename', 'prefix', 'suffix'} +% opt_val - string of new value for feature +%__________________________________________________________________________ +% +% Based on spm_file.m and spm_select.m from SPM12. +%__________________________________________________________________________ + +% Copyright (C) 2011-2018 Guillaume Flandin, Wellcome Centre for Human Neuroimaging + + +if ismember(lower(str), {'list','fplist'}) + [varargout{1:nargout}] = listfiles(str, varargin{:}); + return; +end + +needchar = ischar(str); +options = varargin; + +str = cellstr(str); + +%-Get item +%========================================================================== +if numel(options) == 1 + for n=1:numel(str) + [pth,nam,ext] = fileparts(deblank(str{n})); + switch lower(options{1}) + case 'path' + str{n} = pth; + case 'basename' + str{n} = nam; + case 'ext' + str{n} = ext(2:end); + case 'filename' + str{n} = [nam ext]; + case 'cpath' + str(n) = cpath(str(n)); + case 'fpath' + str{n} = fileparts(char(cpath(str(n)))); + otherwise + error('Unknown option: ''%s''',options{1}); + end + end + options = {}; +end + +%-Set item +%========================================================================== +while ~isempty(options) + for n=1:numel(str) + [pth,nam,ext] = fileparts(deblank(str{n})); + switch lower(options{1}) + case 'path' + pth = char(options{2}); + case 'basename' + nam = char(options{2}); + case 'ext' + ext = char(options{2}); + if ~isempty(ext) && ext(1) ~= '.' + ext = ['.' ext]; + end + case 'filename' + nam = char(options{2}); + ext = ''; + case 'prefix' + nam = [char(options{2}) nam]; + case 'suffix' + nam = [nam char(options{2})]; + otherwise + warning('Unknown item ''%s'': ignored.',lower(options{1})); + end + str{n} = fullfile(pth,[nam ext]); + end + options([1 2]) = []; +end + +if needchar + str = char(str); +end +varargout = {str}; + + +%========================================================================== +%-Canonicalise paths to full path names +%========================================================================== +function t = cpath(t,d) +% canonicalise paths to full path names, removing xxx/./yyy and xxx/../yyy +% constructs +% t must be a cell array of (relative or absolute) paths, d must be a +% single cell containing the base path of relative paths in t +if ispc % valid absolute paths + % Allow drive letter or UNC path + mch = '^([a-zA-Z]:)|(\\\\[^\\]*)'; +else + mch = '^/'; +end +if (nargin<2)||isempty(d), d = {pwd}; end +% Find partial paths, prepend them with d +ppsel = cellfun(@isempty, regexp(t,mch,'once')); +t(ppsel) = cellfun(@(t1)fullfile(d{1},t1),t(ppsel),'UniformOutput',false); +% Break paths into cell lists of folder names +pt = pathparts(t); +% Remove single '.' folder names +sd = cellfun(@(pt1)strcmp(pt1,'.'),pt,'UniformOutput',false); +for cp = 1:numel(pt) + pt{cp} = pt{cp}(~sd{cp}); +end +% Go up one level for '..' folders, don't remove drive letter/server name +% from PC path +if ispc + ptstart = 2; +else + ptstart = 1; +end +for cp = 1:numel(pt) + tmppt = {}; + for cdir = ptstart:numel(pt{cp}) + if strcmp(pt{cp}{cdir},'..') + tmppt = tmppt(1:end-1); + else + tmppt{end+1} = pt{cp}{cdir}; + end + end + if ispc + pt{cp} = [pt{cp}(1) tmppt]; + else + pt{cp} = tmppt; + end +end +% Assemble paths +if ispc + t = cellfun(@(pt1)fullfile(pt1{:}),pt,'UniformOutput',false); +else + t = cellfun(@(pt1)fullfile(filesep,pt1{:}),pt,'UniformOutput',false); +end + + +%========================================================================== +%-Parse paths +%========================================================================== +function pp = pathparts(p) +% parse paths in cellstr p +% returns cell array of path component cellstr arrays +% For PC (WIN) targets, both '\' and '/' are accepted as filesep, similar +% to MATLAB fileparts +if ispc + fs = '\\/'; +else + fs = filesep; +end +pp = cellfun(@(p1)textscan(p1,'%s','delimiter',fs,'MultipleDelimsAsOne',1),p); +if ispc + for k = 1:numel(pp) + if ~isempty(regexp(pp{k}{1}, '^[a-zA-Z]:$', 'once')) + pp{k}{1} = strcat(pp{k}{1}, filesep); + elseif ~isempty(regexp(p{k}, '^\\\\', 'once')) + pp{k}{1} = strcat(filesep, filesep, pp{k}{1}); + end + end +end + + +%========================================================================== +%-List files and directories +%========================================================================== +function [fi, di] = listfiles(action,d,varargin) +% FORMAT [files, dirs] = listfiles('List',dir,regexp) +% FORMAT [files, dirs] = listfiles('FPList',dir,regexp) +% FORMAT [dirs] = listfiles('List',dir,'dir',regexp) +% FORMAT [dirs] = listfiles('FPList',dir,'dir',regexp) + +fi = ''; +di = ''; +switch lower(action) + case 'list' + fp = false; + case 'fplist' + fp = true; + otherwise + error('Invalid action: ''%s''.',action); +end +if nargin < 2 + d = pwd; +else + d = file_utils(d,'cpath'); +end +dirmode = false; +if nargin < 3 + expr = '.*'; +else + if strcmpi(varargin{1},'dir') + dirmode = true; + if nargin < 4 + expr = '.*'; + else + expr = varargin{2}; + end + else + expr = varargin{1}; + end +end +dd = dir(d); +if isempty(dd) + return; +end +fi = sort({dd(~[dd.isdir]).name})'; +di = sort({dd([dd.isdir]).name})'; +di = setdiff(di,{'.','..'}); +if dirmode + t = regexp(di,expr); + if numel(di)==1 && ~iscell(t), t = {t}; end + di = di(~cellfun(@isempty,t)); + fi = di; +else + t = regexp(fi,expr); + if numel(fi)==1 && ~iscell(t), t = {t}; end + fi = fi(~cellfun(@isempty,t)); +end +if fp + fi = cellfun(@(x) fullfile(d,x), fi, 'UniformOutput',false); + di = cellfun(@(x) fullfile(d,x), di, 'UniformOutput',false); +end +fi = char(fi); +di = char(di); diff --git a/lib/utils/parse_filename.m b/lib/utils/parse_filename.m new file mode 100644 index 00000000..7b134f6d --- /dev/null +++ b/lib/utils/parse_filename.m @@ -0,0 +1,56 @@ +function p = parse_filename(filename,fields) +% Split a filename into its building constituents +% FORMAT p = parse_filename(filename,fields) +% +% Example: +% +% >> filename = '../sub-16/anat/sub-16_ses-mri_run-1_echo-2_FLASH.nii.gz'; +% >> parse_filename(filename) +% +% ans = +% +% struct with fields: +% +% filename: 'sub-16_ses-mri_run-1_echo-2_FLASH.nii.gz' +% type: 'FLASH' +% ext: '.nii.gz' +% sub: '16' +% ses: 'mri' +% run: '1' +% echo: '2' +%__________________________________________________________________________ + +% Copyright (C) 2016-2018, Guillaume Flandin, Wellcome Centre for Human Neuroimaging +% Copyright (C) 2018--, BIDS-MATLAB developers + +filename = file_utils(filename,'filename'); + +%-Identify all the BIDS entity-label pairs present in the filename (delimited by "_") +% https://bids-specification.readthedocs.io/en/stable/99-appendices/04-entity-table.html +[parts, dummy] = regexp(filename,'(?:_)+','split','match'); +p.filename = filename; + +%-Identify the suffix and extension of this file +% https://bids-specification.readthedocs.io/en/stable/02-common-principles.html#file-name-structure +[p.type, p.ext] = strtok(parts{end},'.'); + +%-Separate the entity from the label for each pair identified above +for i=1:numel(parts)-1 + [d, dummy] = regexp(parts{i},'(?:\-)+','split','match'); + p.(d{1}) = d{2}; +end + +%-Extra fields can be added to the structure and ordered specifically. +if nargin == 2 + for i=1:numel(fields) + if ~isfield(p,fields{i}) + p.(fields{i}) = ''; + end + end + try + p = orderfields(p,['filename','ext','type',fields]); + catch + warning('Ignoring file ''%s'' not matching template.',filename); + p = struct([]); + end +end From 4b9297cd5bc12b70afb4861d91752d10e972589a Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 23 Jul 2020 14:51:42 +0200 Subject: [PATCH 11/26] update saveEvents to use n/a for missing data --- saveEventsFile.m | 57 ++++++++++++++++++++++----------- tests/test_saveEventsFileSave.m | 26 +++++++++------ 2 files changed, 55 insertions(+), 28 deletions(-) diff --git a/saveEventsFile.m b/saveEventsFile.m index f65503e0..d6c528ac 100644 --- a/saveEventsFile.m +++ b/saveEventsFile.m @@ -43,7 +43,7 @@ % See test_saveEventsFile in the test folder for more details on how to use it. if nargin < 1 - errror('Missing action input'); + error('Missing action input'); end if nargin < 3 || isempty(logFile) @@ -77,13 +77,15 @@ % first with the standard BIDS data and then any extra things for iEvent = 1:size(logFile, 1) - onset = checkInput(logFile(iEvent).onset); - duration = checkInput(logFile(iEvent).duration); - trial_type = checkInput(logFile(iEvent).trial_type); + logFile = checklLogFile('fields', logFile, iEvent); + + onset = logFile(iEvent).onset; + duration = logFile(iEvent).duration; + trial_type = logFile(iEvent).trial_type; if any(isnan([onset trial_type])) || ... any(isempty([onset trial_type])) || ... - any(strcmp({onset, trial_type}, 'NA')) + any(strcmp({onset, trial_type}, 'n/a')) warning('\nSkipping saving this event.\n onset: %f \n trial_type: %s\n', ... onset, ... @@ -91,10 +93,9 @@ else - fprintf(logFile(1).fileID, '%f\t%s\t%f\t', ... - onset, ... - trial_type, ... - duration); + printData(logFile(1).fileID, onset); + printData(logFile(1).fileID, trial_type); + printData(logFile(1).fileID, duration); printExtraColumns(logFile, iEvent); @@ -126,7 +127,7 @@ end -function logFile = checklLogFile(action, logFile) +function logFile = checklLogFile(action, logFile, iEvent) switch action @@ -147,6 +148,16 @@ errorSaveEventsFile('wrongFileID'); end + 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; + end end end @@ -203,7 +214,7 @@ end if ischar(data) && isempty(data) || strcmp(data, ' ') - data = 'NA'; + data = 'n/a'; elseif isempty(data) data = nan; end @@ -232,7 +243,7 @@ function printExtraColumns(logFile, iEvent) % if the field we are looking for does not exist or is empty in the % action logFile structure we will write a NaN otherwise we % write its content - data = 'NA'; + data = 'n/a'; if isfield(logFile, namesExtraColumns{iExtraColumn}) data = logFile(iEvent).(namesExtraColumns{iExtraColumn}); end @@ -242,21 +253,31 @@ function printExtraColumns(logFile, iEvent) if any(isnan(data)) warning('Missing some %s data for this event.', namesExtraColumns{iExtraColumn}); disp(logFile(iEvent)); - elseif all(isnan(data)) || strcmp(data, 'NA') + elseif all(isnan(data)) || strcmp(data, 'n/a') warning('Missing %s data for this event.', namesExtraColumns{iExtraColumn}); disp(logFile(iEvent)); end - if ischar(data) - fprintf(logFile(1).fileID, '%s\t', data); - else - fprintf(logFile(1).fileID, '%f\t', data); - end + printData(logFile(1).fileID, data); end end +function printData(output, data) + if ischar(data) + fprintf(output, '%s\t', data); + else + for i = 1:numel(data) + if isnan(data(i)) + fprintf(output, '%s\t', 'n/a'); + else + fprintf(output, '%f\t', data(i)); + end + end + end +end + function logFile = resetLogFileVar(logFile) logFile(2:end) = []; diff --git a/tests/test_saveEventsFileSave.m b/tests/test_saveEventsFileSave.m index 9fcca9ae..5069475e 100644 --- a/tests/test_saveEventsFileSave.m +++ b/tests/test_saveEventsFileSave.m @@ -16,7 +16,7 @@ function test_saveEventsFileSave() cfg.testingDevice = 'mri'; - [cfg, expParameters] = createFilename(cfg, expParameters); + [cfg, expParameters] = createFilename(cfg, expParameters); %#ok logFile.extraColumns.Speed.length = 1; logFile.extraColumns.LHL24.length = 12; @@ -58,12 +58,18 @@ function test_saveEventsFileSave() logFile(4, 1).onset = 1; logFile(end, 1).trial_type = ''; - % ROW 5: missing info (array is not the right size) + % 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', expParameters, logFile); % close the file @@ -93,20 +99,20 @@ function test_saveEventsFileSave() assert(isequal(C{17}{2}, 'true')); % event 2 / ROW 3: missing info replaced by nans - assert(isequal(C{4}{3}, 'NaN')); - assert(isequal(C{5}{3}, 'NaN')); - assert(isequal(C{16}{3}, 'NaN')); + 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{3}{4}, 'NaN')); - assert(isequal(C{4}{4}, 'NaN')); + assert(isequal(C{3}{4}, 'n/a')); + assert(isequal(C{4}{4}, 'n/a')); % event 4-5 / ROW 5-6: skip empty events - assert(~isequal(C{1}{5}, 'NaN')); + assert(~isequal(C{1}{5}, 'n/a')); % check values entered properly - assert(isequal(C{15}{5}, 'NaN')); - assert(isequal(C{16}{5}, 'NaN')); + assert(isequal(C{15}{5}, 'n/a')); + assert(isequal(C{16}{5}, 'n/a')); end From b5068a43fdc790d42e768665d047608c4652ae71 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 23 Jul 2020 16:58:11 +0200 Subject: [PATCH 12/26] create unit test for checkCFG --- checkCFG.m | 77 +++++++++++++++++++++++++++---------------- tests/test_checkCFG.m | 68 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 29 deletions(-) create mode 100644 tests/test_checkCFG.m diff --git a/checkCFG.m b/checkCFG.m index 85c31527..71277722 100644 --- a/checkCFG.m +++ b/checkCFG.m @@ -11,19 +11,34 @@ '..', ... 'output'); + fieldsToSet = mriDefaults(fieldsToSet); + fieldsToSet.subjectGrp = ''; % in case no group was provided fieldsToSet.sessionNb = 1; % in case no session was provided fieldsToSet.askGrpSess = [true true]; - % BIDS + expParameters = setDefaultFields(expParameters, fieldsToSet); + + %% BIDS + clear fieldsToSet; + fieldsToSet = struct(); fieldsToSet = datasetDescriptionDefaults(fieldsToSet); - fieldsToSet = mriDefaults(fieldsToSet); + expParameters.bids.datasetDescription = ... + setDefaultFields(expParameters.bids.datasetDescription, fieldsToSet); + + clear fieldsToSet; + fieldsToSet = struct(); + fieldsToSet = mriJsonDefaults(fieldsToSet); if isfield(expParameters, 'task') - fieldsToSet.bids.MRI.TaskName = expParameters.task; + fieldsToSet.TaskName = expParameters.task; end - expParameters = setDefaultFields(expParameters, fieldsToSet); + expParameters.bids.MRI = ... + setDefaultFields(expParameters.bids.MRI, fieldsToSet); + + % sort fields alphabetically + expParameters = orderfields(expParameters); %% set the cfg defaults @@ -38,39 +53,43 @@ 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 + +end + function fieldsToSet = datasetDescriptionDefaults(fieldsToSet) % required - fieldsToSet.bids.datasetDescription.json.Name = ''; - fieldsToSet.bids.datasetDescription.json.BIDSVersion = ''; + fieldsToSet.Name = ''; + fieldsToSet.BIDSVersion = ''; % recommended - fieldsToSet.bids.datasetDescription.json.License = ''; - fieldsToSet.bids.datasetDescription.json.Authors = {''}; - fieldsToSet.bids.datasetDescription.json.Acknowledgements = ''; - fieldsToSet.bids.datasetDescription.json.HowToAcknowledge = ''; - fieldsToSet.bids.datasetDescription.json.Funding = {''}; - fieldsToSet.bids.datasetDescription.json.ReferencesAndLinks = {''}; - fieldsToSet.bids.datasetDescription.json.DatasetDOI = ''; + fieldsToSet.License = ''; + fieldsToSet.Authors = {''}; + fieldsToSet.Acknowledgements = ''; + fieldsToSet.HowToAcknowledge = ''; + fieldsToSet.Funding = {''}; + fieldsToSet.ReferencesAndLinks = {''}; + fieldsToSet.DatasetDOI = ''; end -function fieldsToSet = mriDefaults(fieldsToSet) +function fieldsToSet = mriJsonDefaults(fieldsToSet) % for json for funcfional data % required - fieldsToSet.bids.MRI.RepetitionTime = []; - fieldsToSet.bids.MRI.SliceTiming = ''; - fieldsToSet.bids.MRI.TaskName = ''; - fieldsToSet.bids.MRI.PhaseEncodingDirection = ''; - fieldsToSet.bids.MRI.EffectiveEchoSpacing = ''; - fieldsToSet.bids.MRI.EchoTime = ''; + fieldsToSet.RepetitionTime = []; + fieldsToSet.SliceTiming = []; + fieldsToSet.TaskName = []; + % fieldsToSet.PhaseEncodingDirection = []; + % fieldsToSet.EffectiveEchoSpacing = []; + % fieldsToSet.EchoTime = []; % recommended - fieldsToSet.bids.MRI.Instructions = ''; - fieldsToSet.bids.MRI.TaskDescription = ''; - - % 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.Instructions = []; + fieldsToSet.TaskDescription = []; end diff --git a/tests/test_checkCFG.m b/tests/test_checkCFG.m new file mode 100644 index 00000000..b1911f14 --- /dev/null +++ b/tests/test_checkCFG.m @@ -0,0 +1,68 @@ +function test_checkCFG() + + fprintf('\n\n--------------------------------------------------------------------\n\n'); + + clear; + + outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); + + expParameters.subjectNb = 1; + expParameters.runNb = 1; + expParameters.task = 'testtask'; + expParameters.outputDir = outputDir; + + expParameters.bids.datasetDescription.Name = 'dummy'; + expParameters.bids.datasetDescription.BIDSVersion = '1.0.0'; + expParameters.bids.datasetDescription.Authors = {'Jane Doe', 'John Doe'}; + + expParameters.bids.MRI.RepetitionTime = 1.56; + + cfg.testingDevice = 'mri'; + + [~, expParameters] = checkCFG(cfg, expParameters); + + %%% test + + % test data + expectedStructure.subjectNb = 1; + expectedStructure.runNb = 1; + expectedStructure.subjectGrp = ''; + expectedStructure.sessionNb = 1; + + expectedStructure.verbose = 0; + expectedStructure.askGrpSess = [true true]; + + expectedStructure.outputDir = outputDir; + + expectedStructure.task = 'testtask'; + + expectedStructure.MRI.ce = []; + expectedStructure.MRI.dir = []; + expectedStructure.MRI.rec = []; + expectedStructure.MRI.echo = []; + expectedStructure.MRI.acq = []; + + expectedStructure.bids.MRI.RepetitionTime = 1.56; + expectedStructure.bids.MRI.SliceTiming = ''; + expectedStructure.bids.MRI.TaskName = 'testtask'; + expectedStructure.bids.MRI.PhaseEncodingDirection = ''; + expectedStructure.bids.MRI.EffectiveEchoSpacing = ''; + expectedStructure.bids.MRI.EchoTime = ''; + expectedStructure.bids.MRI.Instructions = ''; + expectedStructure.bids.MRI.TaskDescription = ''; + + expectedStructure.bids.datasetDescription.Name = 'dummy'; + expectedStructure.bids.datasetDescription.BIDSVersion = '1.0.0'; + expectedStructure.bids.datasetDescription.License = ''; + expectedStructure.bids.datasetDescription.Authors = {'Jane Doe', 'John Doe'}; + expectedStructure.bids.datasetDescription.Acknowledgements = ''; + expectedStructure.bids.datasetDescription.HowToAcknowledge = ''; + expectedStructure.bids.datasetDescription.Funding = {''}; + expectedStructure.bids.datasetDescription.ReferencesAndLinks = {''}; + expectedStructure.bids.datasetDescription.DatasetDOI = ''; + + expectedStructure = orderfields(expectedStructure); + + assert(isequal(expectedStructure, expParameters)); + +end From bf7caff6397019151ef4bb27b6232ce5e8696022 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 23 Jul 2020 17:00:02 +0200 Subject: [PATCH 13/26] allow for conversion from source to raw --- convertSourceToRaw.m | 69 ++++++++++++++++++++++++++ createFilename.m | 2 +- lib/utils/parse_filename.m | 56 --------------------- saveEventsFile.m | 4 +- tests/makeRawDataset_test.m | 87 +++++++++++++++++++++++++++++++++ tests/test_saveEventsFileOpen.m | 10 ++-- 6 files changed, 164 insertions(+), 64 deletions(-) create mode 100644 convertSourceToRaw.m delete mode 100644 lib/utils/parse_filename.m create mode 100644 tests/makeRawDataset_test.m diff --git a/convertSourceToRaw.m b/convertSourceToRaw.m new file mode 100644 index 00000000..10747eef --- /dev/null +++ b/convertSourceToRaw.m @@ -0,0 +1,69 @@ +function convertSourceToRaw(expParameters) + + sourceDir = fullfile(expParameters.outputDir, 'source'); + rawDir = fullfile(expParameters.outputDir, 'rawdata'); + + % add dummy readme and change file + copyfile(fullfile('..', 'dummyData', 'README'), sourceDir); + copyfile(fullfile('..', 'dummyData', 'CHANGES'), sourceDir); + + copyfile(sourceDir, rawDir); + + % list subjects + subjects = cellstr(file_utils('List', rawDir, 'dir', '^sub-.*$')); + + if isequal(subjects, {''}) + error('No subjects found in BIDS directory.'); + end + + for su = 1:numel(subjects) + + sess = cellstr(file_utils('List', fullfile(rawDir, subjects{su}), 'dir', '^ses-.*$')); + + for se = 1:numel(sess) + parseFunc(rawDir, subjects{su}, sess{se}); + end + + end + +end + +function parseFunc(rawDir, subjName, sesName) + + subjectPath = fullfile(rawDir, subjName, sesName, 'func'); + + if exist(subjectPath, 'dir') + + % do events + filenames = file_utils('List', subjectPath, ... + sprintf('^%s.*_task-.*_events_date-.*$', subjName)); + + removeDateSuffix(filenames, subjectPath); + + % do bold + filenames = file_utils('List', subjectPath, ... + sprintf('^%s.*_task-.*_bold_date-.*$', subjName)); + + removeDateSuffix(filenames, subjectPath); + + end +end + +function removeDateSuffix(filenames, subjectPath) + if isempty(filenames) + filenames = {}; + else + filenames = cellstr(filenames); + end + + for i = 1:numel(filenames) + + [~, name, ext] = fileparts(filenames{i}); + + [parts, ~] = regexp(name, '(?:_date-)+', 'split', 'match'); + + movefile(fullfile(subjectPath, filenames{i}), ... + fullfile(subjectPath, [parts{1} ext])); + + end +end diff --git a/createFilename.m b/createFilename.m index f3c6a944..3df75d1f 100644 --- a/createFilename.m +++ b/createFilename.m @@ -16,7 +16,7 @@ pattern = ['%0' num2str(zeroPadding) '.0f']; expParameters.pattern = pattern; - dateFormat = 'yyyymmdd_HHMM'; + dateFormat = 'yyyymmddHHMM'; expParameters.date = datestr(now, dateFormat); [cfg, expParameters] = checkCFG(cfg, expParameters); diff --git a/lib/utils/parse_filename.m b/lib/utils/parse_filename.m deleted file mode 100644 index 7b134f6d..00000000 --- a/lib/utils/parse_filename.m +++ /dev/null @@ -1,56 +0,0 @@ -function p = parse_filename(filename,fields) -% Split a filename into its building constituents -% FORMAT p = parse_filename(filename,fields) -% -% Example: -% -% >> filename = '../sub-16/anat/sub-16_ses-mri_run-1_echo-2_FLASH.nii.gz'; -% >> parse_filename(filename) -% -% ans = -% -% struct with fields: -% -% filename: 'sub-16_ses-mri_run-1_echo-2_FLASH.nii.gz' -% type: 'FLASH' -% ext: '.nii.gz' -% sub: '16' -% ses: 'mri' -% run: '1' -% echo: '2' -%__________________________________________________________________________ - -% Copyright (C) 2016-2018, Guillaume Flandin, Wellcome Centre for Human Neuroimaging -% Copyright (C) 2018--, BIDS-MATLAB developers - -filename = file_utils(filename,'filename'); - -%-Identify all the BIDS entity-label pairs present in the filename (delimited by "_") -% https://bids-specification.readthedocs.io/en/stable/99-appendices/04-entity-table.html -[parts, dummy] = regexp(filename,'(?:_)+','split','match'); -p.filename = filename; - -%-Identify the suffix and extension of this file -% https://bids-specification.readthedocs.io/en/stable/02-common-principles.html#file-name-structure -[p.type, p.ext] = strtok(parts{end},'.'); - -%-Separate the entity from the label for each pair identified above -for i=1:numel(parts)-1 - [d, dummy] = regexp(parts{i},'(?:\-)+','split','match'); - p.(d{1}) = d{2}; -end - -%-Extra fields can be added to the structure and ordered specifically. -if nargin == 2 - for i=1:numel(fields) - if ~isfield(p,fields{i}) - p.(fields{i}) = ''; - end - end - try - p = orderfields(p,['filename','ext','type',fields]); - catch - warning('Ignoring file ''%s'' not matching template.',filename); - p = struct([]); - end -end diff --git a/saveEventsFile.m b/saveEventsFile.m index d6c528ac..04417443 100644 --- a/saveEventsFile.m +++ b/saveEventsFile.m @@ -94,8 +94,8 @@ else printData(logFile(1).fileID, onset); - printData(logFile(1).fileID, trial_type); printData(logFile(1).fileID, duration); + printData(logFile(1).fileID, trial_type); printExtraColumns(logFile, iEvent); @@ -174,7 +174,7 @@ 'w'); % print the basic BIDS columns - fprintf(logFile.fileID, '%s\t%s\t%s\t', 'onset', 'trial_type', 'duration'); + fprintf(logFile.fileID, '%s\t%s\t%s\t', 'onset', 'duration', 'trial_type'); logFile = printHeaderExtraColumns(logFile); diff --git a/tests/makeRawDataset_test.m b/tests/makeRawDataset_test.m new file mode 100644 index 00000000..a55774a4 --- /dev/null +++ b/tests/makeRawDataset_test.m @@ -0,0 +1,87 @@ +function test_makeRawDataset() + + fprintf('\n\n--------------------------------------------------------------------\n\n'); + + clear; + + outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); + + if isdir(outputDir) + rmdir(outputDir, 's'); + end + + %% set up + + %%% set up + + expParameters.subjectNb = 1; + expParameters.runNb = 1; + expParameters.task = 'testtask'; + expParameters.outputDir = outputDir; + + expParameters.bids.datasetDescription.Name = 'dummy'; + expParameters.bids.datasetDescription.BIDSVersion = '1.0.0'; + expParameters.bids.datasetDescription.Authors = {'Jane Doe', 'John Doe'}; + + expParameters.bids.MRI.RepetitionTime = 1.56; + + cfg.testingDevice = 'mri'; + + logFile.extraColumns.Speed.length = 1; + logFile.extraColumns.LHL24.length = 3; + logFile.extraColumns.is_Fixation.length = 1; + + %%% do stuff + + [cfg, expParameters] = createFilename(cfg, expParameters); %#ok<*ASGLU> + + % create the events file and header + logFile = saveEventsFile('open', expParameters, logFile); + + createDataDictionary(expParameters, logFile); + createBoldJson(expParameters); + createDatasetDescription(expParameters); + + % ROW 2: normal events : all info is there + logFile(1, 1).onset = 2; + logFile(end, 1).trial_type = 'MotionUp'; + logFile(end, 1).duration = 3; + logFile(end, 1).Speed = 2; + logFile(end, 1).is_Fixation = true; + logFile(end, 1).LHL24 = 1:3; + + % 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 = 'BLUES'; + logFile(end, 1).Speed = []; + logFile(end, 1).is_Fixation = true; + logFile(end, 1).LHL24 = rand(1, 3); + + % ROW 5: missing info (array is not the right size) + logFile(5, 1).onset = 5; + logFile(end, 1).trial_type = 'jazz'; + logFile(end, 1).duration = 3; + logFile(end, 1).LHL24 = rand(1, 2); + + saveEventsFile('save', expParameters, logFile); + + % close the file + saveEventsFile('close', expParameters, logFile); + + % add dummy functional data + funcDir = fullfile(expParameters.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'), ... + fullfile(funcDir, boldFilename)); + + %% + + convertSourceToRaw(expParameters); +end diff --git a/tests/test_saveEventsFileOpen.m b/tests/test_saveEventsFileOpen.m index c4435567..f309000a 100644 --- a/tests/test_saveEventsFileOpen.m +++ b/tests/test_saveEventsFileOpen.m @@ -42,8 +42,8 @@ function test_saveEventsFileOpen() % check the extra columns of the header assert(isequal(C{1}{1}, 'onset')); - assert(isequal(C{2}{1}, 'trial_type')); - assert(isequal(C{3}{1}, 'duration')); + assert(isequal(C{2}{1}, 'duration')); + assert(isequal(C{3}{1}, 'trial_type')); %% check header writing with extra columns fprintf('\n\n--------------------------------------------------------------------\n\n'); @@ -66,7 +66,7 @@ function test_saveEventsFileOpen() %%% do stuff - [cfg, expParameters] = createFilename(cfg, expParameters); + [cfg, expParameters] = createFilename(cfg, expParameters); %#ok % create the events file and header logFile = saveEventsFile('open', expParameters, logFile); @@ -87,8 +87,8 @@ function test_saveEventsFileOpen() % check the extra columns of the header assert(isequal(C{1}{1}, 'onset')); - assert(isequal(C{2}{1}, 'trial_type')); - assert(isequal(C{3}{1}, 'duration')); + assert(isequal(C{2}{1}, 'duration')); + assert(isequal(C{3}{1}, 'trial_type')); assert(isequal(C{4}{1}, 'Speed')); assert(isequal(C{5}{1}, 'is_Fixation')); From 840d42b0a81efff9ac9f3355a3f0551ba8228506 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 23 Jul 2020 17:09:28 +0200 Subject: [PATCH 14/26] fix minor bugs --- checkCFG.m | 1 + tests/makeRawDataset_test.m | 2 +- tests/test_saveEventsFileSave.m | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/checkCFG.m b/checkCFG.m index 71277722..8e374b13 100644 --- a/checkCFG.m +++ b/checkCFG.m @@ -34,6 +34,7 @@ fieldsToSet.TaskName = expParameters.task; end + expParameters.bids.MRI = struct(); expParameters.bids.MRI = ... setDefaultFields(expParameters.bids.MRI, fieldsToSet); diff --git a/tests/makeRawDataset_test.m b/tests/makeRawDataset_test.m index a55774a4..1cc0c292 100644 --- a/tests/makeRawDataset_test.m +++ b/tests/makeRawDataset_test.m @@ -1,4 +1,4 @@ -function test_makeRawDataset() +function makeRawDataset_test() fprintf('\n\n--------------------------------------------------------------------\n\n'); diff --git a/tests/test_saveEventsFileSave.m b/tests/test_saveEventsFileSave.m index 5069475e..41067d3b 100644 --- a/tests/test_saveEventsFileSave.m +++ b/tests/test_saveEventsFileSave.m @@ -91,8 +91,8 @@ function test_saveEventsFileSave() % event 1/ ROW 2: check that values are entered correctly assert(isequal(C{1}{2}, sprintf('%f', 2))); - assert(isequal(C{2}{2}, 'motion_up')); - assert(isequal(C{3}{2}, sprintf('%f', 3))); + assert(isequal(C{3}{2}, 'motion_up')); + assert(isequal(C{2}{2}, sprintf('%f', 3))); assert(isequal(C{4}{2}, sprintf('%f', 2))); assert(isequal(C{5}{2}, sprintf('%f', 1))); assert(isequal(C{16}{2}, sprintf('%f', 12))); @@ -105,7 +105,7 @@ function test_saveEventsFileSave() assert(isequal(C{17}{3}, 'false')); % event 3 / ROW 4: missing info (duration is missing and speed is empty) - assert(isequal(C{3}{4}, 'n/a')); + assert(isequal(C{2}{4}, 'n/a')); assert(isequal(C{4}{4}, 'n/a')); % event 4-5 / ROW 5-6: skip empty events From 8c22ff2741902fe8b638c0f954bb2b09cd9ce717 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 23 Jul 2020 17:16:24 +0200 Subject: [PATCH 15/26] update travis.yml --- .travis.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5c9e6e2f..33d09032 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,8 +13,8 @@ before_install: - travis_retry sudo apt-get -y -qq update - travis_retry sudo apt-get -y install octave - travis_retry sudo apt-get -y install liboctave-dev - # - travis_retry sudo apt-get -y install nodejs - # - travis_retry sudo apt-get -y install npm + - travis_retry sudo apt-get -y install nodejs + - travis_retry sudo apt-get -y install npm - cd .. && git clone https://github.com/florianschanda/miss_hit.git && export PATH=$PATH:`pwd`/miss_hit && cd CPP_BIDS @@ -26,7 +26,7 @@ install: # Install BIDS-MATLAB - octave $OCTFLAGS --eval "addpath (pwd); savepath ();" # Install BIDS-Validator - #- sudo npm install -g bids-validator + - sudo npm install -g bids-validator before_script: # Change current directory @@ -38,4 +38,8 @@ jobs: name: "Unit Tests" # names the first job script: octave $OCTFLAGS --eval "results = runTests; assert(all(~[results.Failed]))" - script: cd .. && mh_style.py `pwd` - name: "miss_hit linter" # names the second job \ No newline at end of file + name: "miss_hit linter" # names the second job + - stage: "BIDS validator" + name: "create and check dataset" # names the second job + - script: octave $OCTFLAGS --eval "makeRawDataset_test" && bids-validator `pwd`/../output/rawdata/ --ignoreNiftiHeaders + \ No newline at end of file From 5d5a5404ea2ca8a0a536ead92c9772e5af97d0d3 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 23 Jul 2020 17:49:56 +0200 Subject: [PATCH 16/26] intialize structure in checkCFG --- checkCFG.m | 12 ++++++++++-- tests/test_checkCFG.m | 9 ++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/checkCFG.m b/checkCFG.m index 8e374b13..a1d4a9b1 100644 --- a/checkCFG.m +++ b/checkCFG.m @@ -16,10 +16,19 @@ fieldsToSet.subjectGrp = ''; % in case no group was provided fieldsToSet.sessionNb = 1; % in case no session was provided fieldsToSet.askGrpSess = [true true]; - + expParameters = setDefaultFields(expParameters, fieldsToSet); %% BIDS + fieldsToSet.bids = struct(); + expParameters = setDefaultFields(expParameters, fieldsToSet); + + clear fieldsToSet; + fieldsToSet = struct(); + fieldsToSet.MRI = struct(); + fieldsToSet.datasetDescription = struct(); + expParameters.bids = setDefaultFields(expParameters.bids, fieldsToSet); + clear fieldsToSet; fieldsToSet = struct(); fieldsToSet = datasetDescriptionDefaults(fieldsToSet); @@ -34,7 +43,6 @@ fieldsToSet.TaskName = expParameters.task; end - expParameters.bids.MRI = struct(); expParameters.bids.MRI = ... setDefaultFields(expParameters.bids.MRI, fieldsToSet); diff --git a/tests/test_checkCFG.m b/tests/test_checkCFG.m index b1911f14..3f81958c 100644 --- a/tests/test_checkCFG.m +++ b/tests/test_checkCFG.m @@ -45,9 +45,9 @@ function test_checkCFG() expectedStructure.bids.MRI.RepetitionTime = 1.56; expectedStructure.bids.MRI.SliceTiming = ''; expectedStructure.bids.MRI.TaskName = 'testtask'; - expectedStructure.bids.MRI.PhaseEncodingDirection = ''; - expectedStructure.bids.MRI.EffectiveEchoSpacing = ''; - expectedStructure.bids.MRI.EchoTime = ''; +% expectedStructure.bids.MRI.PhaseEncodingDirection = ''; +% expectedStructure.bids.MRI.EffectiveEchoSpacing = ''; +% expectedStructure.bids.MRI.EchoTime = ''; expectedStructure.bids.MRI.Instructions = ''; expectedStructure.bids.MRI.TaskDescription = ''; @@ -62,6 +62,9 @@ function test_checkCFG() expectedStructure.bids.datasetDescription.DatasetDOI = ''; expectedStructure = orderfields(expectedStructure); + + expectedStructure.bids.MRI + expParameters.bids.MRI assert(isequal(expectedStructure, expParameters)); From 45686ac34b6fac9d133c3f9f2e077609fec0fe20 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 23 Jul 2020 17:50:41 +0200 Subject: [PATCH 17/26] mh autofix --- checkCFG.m | 6 +++--- tests/test_checkCFG.m | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/checkCFG.m b/checkCFG.m index a1d4a9b1..2b93a7dc 100644 --- a/checkCFG.m +++ b/checkCFG.m @@ -16,19 +16,19 @@ fieldsToSet.subjectGrp = ''; % in case no group was provided fieldsToSet.sessionNb = 1; % in case no session was provided fieldsToSet.askGrpSess = [true true]; - + expParameters = setDefaultFields(expParameters, fieldsToSet); %% BIDS fieldsToSet.bids = struct(); expParameters = setDefaultFields(expParameters, fieldsToSet); - + clear fieldsToSet; fieldsToSet = struct(); fieldsToSet.MRI = struct(); fieldsToSet.datasetDescription = struct(); expParameters.bids = setDefaultFields(expParameters.bids, fieldsToSet); - + clear fieldsToSet; fieldsToSet = struct(); fieldsToSet = datasetDescriptionDefaults(fieldsToSet); diff --git a/tests/test_checkCFG.m b/tests/test_checkCFG.m index 3f81958c..78da308d 100644 --- a/tests/test_checkCFG.m +++ b/tests/test_checkCFG.m @@ -45,9 +45,9 @@ function test_checkCFG() expectedStructure.bids.MRI.RepetitionTime = 1.56; expectedStructure.bids.MRI.SliceTiming = ''; expectedStructure.bids.MRI.TaskName = 'testtask'; -% expectedStructure.bids.MRI.PhaseEncodingDirection = ''; -% expectedStructure.bids.MRI.EffectiveEchoSpacing = ''; -% expectedStructure.bids.MRI.EchoTime = ''; + % expectedStructure.bids.MRI.PhaseEncodingDirection = ''; + % expectedStructure.bids.MRI.EffectiveEchoSpacing = ''; + % expectedStructure.bids.MRI.EchoTime = ''; expectedStructure.bids.MRI.Instructions = ''; expectedStructure.bids.MRI.TaskDescription = ''; @@ -62,9 +62,9 @@ function test_checkCFG() expectedStructure.bids.datasetDescription.DatasetDOI = ''; expectedStructure = orderfields(expectedStructure); - - expectedStructure.bids.MRI - expParameters.bids.MRI + + expectedStructure.bids.MRI; + expParameters.bids.MRI; assert(isequal(expectedStructure, expParameters)); From d05f810fbc76a031665ba655b826eff44965b6a2 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 23 Jul 2020 18:32:02 +0200 Subject: [PATCH 18/26] prettify output tests --- tests/makeRawDataset_test.m | 14 ++++++++------ tests/runTests.m | 3 ++- tests/test_checkCFG.m | 2 -- tests/test_createBoldJson.m | 2 -- tests/test_createDataDictionary.m | 2 -- tests/test_createDatasetDescription.m | 2 -- tests/test_createFilename.m | 5 ++--- tests/test_initializeExtraColumns.m | 10 ++++++---- tests/test_saveEventsFileOpen.m | 4 +--- tests/test_saveEventsFileOpenMultiColumn.m | 2 -- tests/test_saveEventsFileSave.m | 2 -- 11 files changed, 19 insertions(+), 29 deletions(-) diff --git a/tests/makeRawDataset_test.m b/tests/makeRawDataset_test.m index 1cc0c292..e6ffde14 100644 --- a/tests/makeRawDataset_test.m +++ b/tests/makeRawDataset_test.m @@ -23,9 +23,11 @@ function makeRawDataset_test() expParameters.bids.datasetDescription.BIDSVersion = '1.0.0'; expParameters.bids.datasetDescription.Authors = {'Jane Doe', 'John Doe'}; - expParameters.bids.MRI.RepetitionTime = 1.56; + % expParameters.bids.MRI.RepetitionTime = 1.56; + % + % cfg.testingDevice = 'mri'; - cfg.testingDevice = 'mri'; + cfg.testingDevice = 'pc'; logFile.extraColumns.Speed.length = 1; logFile.extraColumns.LHL24.length = 3; @@ -39,7 +41,7 @@ function makeRawDataset_test() logFile = saveEventsFile('open', expParameters, logFile); createDataDictionary(expParameters, logFile); - createBoldJson(expParameters); + % createBoldJson(expParameters); createDatasetDescription(expParameters); % ROW 2: normal events : all info is there @@ -77,9 +79,9 @@ function makeRawDataset_test() % add dummy functional data funcDir = fullfile(expParameters.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'), ... - fullfile(funcDir, boldFilename)); + % copyfile( ... + % fullfile('..', 'dummyData', 'dummyData.nii.gz'), ... + % fullfile(funcDir, boldFilename)); %% diff --git a/tests/runTests.m b/tests/runTests.m index 3c9e3a38..b53a104f 100644 --- a/tests/runTests.m +++ b/tests/runTests.m @@ -30,8 +30,9 @@ % -Run each test file and catch error message in case of failure try - + fprintf('\n\n--------------------------------------------------------------------\n'); fprintf('%s', d(i).name(1:end - 2)); + fprintf('\n--------------------------------------------------------------------\n'); feval(d(i).name(1:end - 2)); results(i).Passed = true; diff --git a/tests/test_checkCFG.m b/tests/test_checkCFG.m index 78da308d..0ed2e05c 100644 --- a/tests/test_checkCFG.m +++ b/tests/test_checkCFG.m @@ -1,7 +1,5 @@ function test_checkCFG() - fprintf('\n\n--------------------------------------------------------------------\n\n'); - clear; outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); diff --git a/tests/test_createBoldJson.m b/tests/test_createBoldJson.m index 91bb3957..6ee9bb07 100644 --- a/tests/test_createBoldJson.m +++ b/tests/test_createBoldJson.m @@ -1,7 +1,5 @@ function test_createBoldJson() - fprintf('\n\n--------------------------------------------------------------------\n\n'); - outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); %%% set up part diff --git a/tests/test_createDataDictionary.m b/tests/test_createDataDictionary.m index 130d99b1..636371de 100644 --- a/tests/test_createDataDictionary.m +++ b/tests/test_createDataDictionary.m @@ -1,7 +1,5 @@ function test_createDataDictionary() - fprintf('\n\n--------------------------------------------------------------------\n\n'); - clear; outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); diff --git a/tests/test_createDatasetDescription.m b/tests/test_createDatasetDescription.m index f5fdbefe..07ee42f5 100644 --- a/tests/test_createDatasetDescription.m +++ b/tests/test_createDatasetDescription.m @@ -1,7 +1,5 @@ function test_createDatasetDescription() - fprintf('\n\n--------------------------------------------------------------------\n\n'); - outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); %%% set up part diff --git a/tests/test_createFilename.m b/tests/test_createFilename.m index a9fec298..171ed583 100644 --- a/tests/test_createFilename.m +++ b/tests/test_createFilename.m @@ -2,7 +2,6 @@ function test_createFilename() % test for filename creation and their directories %% PC - fprintf('\n\n--------------------------------------------------------------------\n\n'); outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); @@ -41,7 +40,7 @@ function test_createFilename() assert(strcmp(expParameters.fileName.stim, stimFilename)); %% fMRI and eye tracker - fprintf('\n\n--------------------------------------------------------------------\n\n'); + fprintf('\n--------------------------------------------------------------------'); clear; @@ -84,7 +83,7 @@ function test_createFilename() assert(strcmp(expParameters.fileName.eyetracker, eyetrackerFilename)); %% EEG - fprintf('\n\n--------------------------------------------------------------------\n\n'); + fprintf('\n--------------------------------------------------------------------'); clear; diff --git a/tests/test_initializeExtraColumns.m b/tests/test_initializeExtraColumns.m index 694ce2f6..4a4c75db 100644 --- a/tests/test_initializeExtraColumns.m +++ b/tests/test_initializeExtraColumns.m @@ -1,6 +1,6 @@ function test_initializeExtraColumns() - fprintf('\n\n--------------------------------------------------------------------\n\n'); + %% clear; @@ -18,8 +18,9 @@ function test_initializeExtraColumns() assert(isequal(expectedStrcut, logFile)); - fprintf('\n\n--------------------------------------------------------------------\n\n'); - + %% + fprintf('\n--------------------------------------------------------------------'); + clear; %%% set up @@ -38,7 +39,8 @@ function test_initializeExtraColumns() assert(isequal(expectedStrcut, logFile)); - fprintf('\n\n--------------------------------------------------------------------\n\n'); + %% + fprintf('\n--------------------------------------------------------------------'); clear; diff --git a/tests/test_saveEventsFileOpen.m b/tests/test_saveEventsFileOpen.m index f309000a..21d52954 100644 --- a/tests/test_saveEventsFileOpen.m +++ b/tests/test_saveEventsFileOpen.m @@ -1,8 +1,6 @@ function test_saveEventsFileOpen() %% Initialize file - fprintf('\n\n--------------------------------------------------------------------\n\n'); - clear; outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); @@ -46,7 +44,7 @@ function test_saveEventsFileOpen() assert(isequal(C{3}{1}, 'trial_type')); %% check header writing with extra columns - fprintf('\n\n--------------------------------------------------------------------\n\n'); + fprintf('\n\n--------------------------------------------------------------------'); clear; diff --git a/tests/test_saveEventsFileOpenMultiColumn.m b/tests/test_saveEventsFileOpenMultiColumn.m index ee3fd117..d1415fbf 100644 --- a/tests/test_saveEventsFileOpenMultiColumn.m +++ b/tests/test_saveEventsFileOpenMultiColumn.m @@ -1,8 +1,6 @@ function test_saveEventsFileOpenMultiColumn() %% check header writing with several columns for one variable - fprintf('\n\n--------------------------------------------------------------------\n\n'); - clear; outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); diff --git a/tests/test_saveEventsFileSave.m b/tests/test_saveEventsFileSave.m index 41067d3b..ad3bfe84 100644 --- a/tests/test_saveEventsFileSave.m +++ b/tests/test_saveEventsFileSave.m @@ -1,8 +1,6 @@ function test_saveEventsFileSave() %% write things in it - fprintf('\n\n--------------------------------------------------------------------\n\n'); - clear; outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); From 0be3d2c3bb908b8a74323794ed3b301c9f8265db Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 24 Jul 2020 16:41:36 +0200 Subject: [PATCH 19/26] refactor and add some tests --- checkCFG.m | 19 ++++--- saveEventsFile.m | 54 ++++++++++++++----- tests/makeRawDataset_test.m | 14 ++--- tests/test_checkCFG.m | 54 +++++++++++++------ ...traColumns.m => test_saveEventsFileInit.m} | 23 ++++---- 5 files changed, 111 insertions(+), 53 deletions(-) rename tests/{test_initializeExtraColumns.m => test_saveEventsFileInit.m} (80%) diff --git a/checkCFG.m b/checkCFG.m index 2b93a7dc..e28c8f5c 100644 --- a/checkCFG.m +++ b/checkCFG.m @@ -3,6 +3,13 @@ checkCppBidsDependencies(); + if nargin < 1 || isempty(cfg) + cfg = struct(); + end + if nargin < 2 || isempty(expParameters) + expParameters = struct(); + end + %% set the expParameters defaults fieldsToSet.verbose = 0; @@ -20,25 +27,23 @@ expParameters = setDefaultFields(expParameters, fieldsToSet); %% BIDS + clear fieldsToSet; fieldsToSet.bids = struct(); expParameters = setDefaultFields(expParameters, fieldsToSet); clear fieldsToSet; - fieldsToSet = struct(); fieldsToSet.MRI = struct(); fieldsToSet.datasetDescription = struct(); expParameters.bids = setDefaultFields(expParameters.bids, fieldsToSet); clear fieldsToSet; - fieldsToSet = struct(); - fieldsToSet = datasetDescriptionDefaults(fieldsToSet); + fieldsToSet = datasetDescriptionDefaults(); expParameters.bids.datasetDescription = ... setDefaultFields(expParameters.bids.datasetDescription, fieldsToSet); clear fieldsToSet; - fieldsToSet = struct(); - fieldsToSet = mriJsonDefaults(fieldsToSet); + fieldsToSet = mriJsonDefaults(); if isfield(expParameters, 'task') fieldsToSet.TaskName = expParameters.task; end @@ -73,7 +78,7 @@ end -function fieldsToSet = datasetDescriptionDefaults(fieldsToSet) +function fieldsToSet = datasetDescriptionDefaults() % required fieldsToSet.Name = ''; fieldsToSet.BIDSVersion = ''; @@ -87,7 +92,7 @@ fieldsToSet.DatasetDOI = ''; end -function fieldsToSet = mriJsonDefaults(fieldsToSet) +function fieldsToSet = mriJsonDefaults() % for json for funcfional data % required diff --git a/saveEventsFile.m b/saveEventsFile.m index 04417443..78dcefaa 100644 --- a/saveEventsFile.m +++ b/saveEventsFile.m @@ -46,24 +46,28 @@ error('Missing action input'); end + if nargin < 2 + expParameters = struct(); + end + if nargin < 3 || isempty(logFile) logFile = checklLogFile('init'); end switch action - case 'open' + case 'init' logFile = initializeExtraColumns(logFile); + case 'open' + logFile.filename = expParameters.fileName.events; logFile = initializeFile(expParameters, logFile); case 'open_stim' - logFile = initializeExtraColumns(logFile); - logFile.filename = expParameters.fileName.stim; logFile = initializeFile(expParameters, logFile); @@ -145,10 +149,11 @@ case 'type&size' if ~isstruct(logFile) || size(logFile, 2) > 1 - errorSaveEventsFile('wrongFileID'); + errorSaveEventsFile('wrongLogSize'); end case 'fields' + if ~isfield(logFile, 'onset') || isempty(logFile(iEvent).onset) logFile(iEvent).onset = nan; end @@ -158,12 +163,17 @@ if ~isfield(logFile, 'duration') || isempty(logFile(iEvent).duration) logFile(iEvent).duration = nan; end + + logFile = checkExtracolumns(logFile, iEvent); + end end function logFile = initializeFile(expParameters, logFile) + logFile = initializeExtraColumns(logFile); + % Initialize txt logfiles and empty fields for the standard BIDS % event file logFile.fileID = fopen( ... @@ -176,14 +186,14 @@ % print the basic BIDS columns fprintf(logFile.fileID, '%s\t%s\t%s\t', 'onset', 'duration', 'trial_type'); - logFile = printHeaderExtraColumns(logFile); + printHeaderExtraColumns(logFile); % next line so we start printing at the right place fprintf(logFile.fileID, '\n'); end -function logFile = printHeaderExtraColumns(logFile) +function printHeaderExtraColumns(logFile) % print any extra column specified by the user [namesExtraColumns, logFile] = returnNamesExtraColumns(logFile); @@ -206,7 +216,7 @@ function data = checkInput(data, expectedLength) % check the data to write - % default will be 'NA' for chars and NaN for numeric data + % 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 @@ -216,6 +226,8 @@ if ischar(data) && isempty(data) || strcmp(data, ' ') data = 'n/a'; elseif isempty(data) + % important to not set this to n/a as we still need to check if this + % numeric valur has the right length and needs to be nan padded data = nan; end @@ -232,7 +244,11 @@ end -function printExtraColumns(logFile, iEvent) +function logFile = checkExtracolumns(logFile, iEvent) + % loops through the extra columns + % if the field we are looking for does not exist or is empty in the + % action logFile structure we will write a n/a + % otherwise we write its content namesExtraColumns = returnNamesExtraColumns(logFile); @@ -240,9 +256,6 @@ function printExtraColumns(logFile, iEvent) nbCol = returnNbColumns(logFile, namesExtraColumns{iExtraColumn}); - % if the field we are looking for does not exist or is empty in the - % action logFile structure we will write a NaN otherwise we - % write its content data = 'n/a'; if isfield(logFile, namesExtraColumns{iExtraColumn}) data = logFile(iEvent).(namesExtraColumns{iExtraColumn}); @@ -250,6 +263,8 @@ function printExtraColumns(logFile, iEvent) data = checkInput(data, nbCol); + logFile(iEvent).(namesExtraColumns{iExtraColumn}) = data; + if any(isnan(data)) warning('Missing some %s data for this event.', namesExtraColumns{iExtraColumn}); disp(logFile(iEvent)); @@ -258,6 +273,19 @@ function printExtraColumns(logFile, iEvent) disp(logFile(iEvent)); end + end + +end + +function printExtraColumns(logFile, iEvent) + % loops through the extra columns and print them + + namesExtraColumns = returnNamesExtraColumns(logFile); + + for iExtraColumn = 1:numel(namesExtraColumns) + + data = logFile(iEvent).(namesExtraColumns{iExtraColumn}); + printData(logFile(1).fileID, data); end @@ -265,6 +293,8 @@ function printExtraColumns(logFile, iEvent) end function printData(output, data) + % write char + % for numeric data we replace any nan by n/a if ischar(data) fprintf(output, '%s\t', data); else @@ -305,7 +335,7 @@ function errorSaveEventsFile(identifier) case 'missingFileID' errorStruct.message = 'logFile must contain a valid fileID field'; - case 'wrongFileID' + case 'wrongLogSize' errorStruct.message = 'logFile must be a nx1 structure'; end diff --git a/tests/makeRawDataset_test.m b/tests/makeRawDataset_test.m index e6ffde14..137a8353 100644 --- a/tests/makeRawDataset_test.m +++ b/tests/makeRawDataset_test.m @@ -23,9 +23,9 @@ function makeRawDataset_test() expParameters.bids.datasetDescription.BIDSVersion = '1.0.0'; expParameters.bids.datasetDescription.Authors = {'Jane Doe', 'John Doe'}; - % expParameters.bids.MRI.RepetitionTime = 1.56; - % - % cfg.testingDevice = 'mri'; + expParameters.bids.MRI.RepetitionTime = 1.56; + + cfg.testingDevice = 'mri'; cfg.testingDevice = 'pc'; @@ -41,7 +41,7 @@ function makeRawDataset_test() logFile = saveEventsFile('open', expParameters, logFile); createDataDictionary(expParameters, logFile); - % createBoldJson(expParameters); + createBoldJson(expParameters); createDatasetDescription(expParameters); % ROW 2: normal events : all info is there @@ -79,9 +79,9 @@ function makeRawDataset_test() % add dummy functional data funcDir = fullfile(expParameters.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'), ... - % fullfile(funcDir, boldFilename)); + copyfile( ... + fullfile('..', 'dummyData', 'dummyData.nii.gz'), ... + fullfile(funcDir, boldFilename)); %% diff --git a/tests/test_checkCFG.m b/tests/test_checkCFG.m index 0ed2e05c..2db865f2 100644 --- a/tests/test_checkCFG.m +++ b/tests/test_checkCFG.m @@ -1,5 +1,16 @@ function test_checkCFG() + expParameters.outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); + [cfg, expParameters] = checkCFG([], expParameters); + + expectedStructure = returnExpectedStructure(); + expectedStructure.outputDir = expParameters.outputDir; + + assert(isequal(expectedStructure, expParameters)); + + %% + fprintf('\n--------------------------------------------------------------------'); + clear; outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); @@ -22,37 +33,56 @@ function test_checkCFG() %%% test % test data + expectedStructure = returnExpectedStructure(); expectedStructure.subjectNb = 1; expectedStructure.runNb = 1; + + expectedStructure.outputDir = outputDir; + + expectedStructure.task = 'testtask'; + + expectedStructure.bids.MRI.RepetitionTime = 1.56; + expectedStructure.bids.MRI.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, expParameters)); + + fprintf('\n'); + +end + +function expectedStructure = returnExpectedStructure() + expectedStructure.subjectGrp = ''; expectedStructure.sessionNb = 1; expectedStructure.verbose = 0; expectedStructure.askGrpSess = [true true]; - expectedStructure.outputDir = outputDir; - - expectedStructure.task = 'testtask'; - expectedStructure.MRI.ce = []; expectedStructure.MRI.dir = []; expectedStructure.MRI.rec = []; expectedStructure.MRI.echo = []; expectedStructure.MRI.acq = []; - expectedStructure.bids.MRI.RepetitionTime = 1.56; + expectedStructure.bids.MRI.RepetitionTime = []; expectedStructure.bids.MRI.SliceTiming = ''; - expectedStructure.bids.MRI.TaskName = 'testtask'; + 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 = 'dummy'; - expectedStructure.bids.datasetDescription.BIDSVersion = '1.0.0'; + expectedStructure.bids.datasetDescription.Name = ''; + expectedStructure.bids.datasetDescription.BIDSVersion = ''; expectedStructure.bids.datasetDescription.License = ''; - expectedStructure.bids.datasetDescription.Authors = {'Jane Doe', 'John Doe'}; + expectedStructure.bids.datasetDescription.Authors = {''}; expectedStructure.bids.datasetDescription.Acknowledgements = ''; expectedStructure.bids.datasetDescription.HowToAcknowledge = ''; expectedStructure.bids.datasetDescription.Funding = {''}; @@ -60,10 +90,4 @@ function test_checkCFG() expectedStructure.bids.datasetDescription.DatasetDOI = ''; expectedStructure = orderfields(expectedStructure); - - expectedStructure.bids.MRI; - expParameters.bids.MRI; - - assert(isequal(expectedStructure, expParameters)); - end diff --git a/tests/test_initializeExtraColumns.m b/tests/test_saveEventsFileInit.m similarity index 80% rename from tests/test_initializeExtraColumns.m rename to tests/test_saveEventsFileInit.m index 4a4c75db..765f96f3 100644 --- a/tests/test_initializeExtraColumns.m +++ b/tests/test_saveEventsFileInit.m @@ -1,16 +1,13 @@ -function test_initializeExtraColumns() +function test_saveEventsFileInit() %% - clear; - %%% set up - checkCppBidsDependencies(); - logFile = struct('filename', [], 'extraColumns', cell(1)); - logFile(1).filename = ''; + % make sure the dependencies are there + checkCFG(); %%% do stuff - logFile = initializeExtraColumns(logFile); + [logFile] = saveEventsFile('init'); %%% test section expectedStrcut(1).filename = ''; @@ -20,15 +17,15 @@ function test_initializeExtraColumns() %% fprintf('\n--------------------------------------------------------------------'); - + clear; %%% set up - checkCppBidsDependencies(); + [cfg, expParameters] = checkCFG(); %#ok logFile.extraColumns = {'Speed'}; %%% do stuff - logFile = initializeExtraColumns(logFile); + [logFile] = saveEventsFile('init', expParameters, logFile); %%% test section expectedStrcut(1).extraColumns.Speed.length = 1; @@ -45,12 +42,12 @@ function test_initializeExtraColumns() clear; %%% set up - checkCppBidsDependencies(); + [cfg, expParameters] = checkCFG(); %#ok logFile.extraColumns.Speed.length = 1; logFile.extraColumns.LHL24.length = 3; %%% do stuff - logFile = initializeExtraColumns(logFile); + [logFile] = saveEventsFile('init', expParameters, logFile); %%% test section expectedStrcut(1).extraColumns.Speed.length = 1; @@ -66,4 +63,6 @@ function test_initializeExtraColumns() assert(isequal(expectedStrcut, logFile)); + fprintf('\n'); + end From 261c5d2e582c39aa4b5fa62c4abbacae3b602f78 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 24 Jul 2020 16:51:13 +0200 Subject: [PATCH 20/26] fix linter and travis --- .travis.yml | 2 +- tests/{makeRawDataset_test.m => test_makeRawDataset.m} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename tests/{makeRawDataset_test.m => test_makeRawDataset.m} (98%) diff --git a/.travis.yml b/.travis.yml index 33d09032..304e7d5c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,7 +21,7 @@ before_install: install: # Install JSONio #- travis_retry git clone git://github.com/gllmflndn/JSONio.git --depth 1 - #- cd JSONio; mkoctfile --mex jsonread.c jsmn.c -DJSMN_PARENT_LINKS; cd .. + - cd lib/JSONio; mkoctfile --mex jsonread.c jsmn.c -DJSMN_PARENT_LINKS; cd ../.. #- octave $OCTFLAGS --eval "addpath (fullfile (pwd, 'JSONio')); savepath ();" # Install BIDS-MATLAB - octave $OCTFLAGS --eval "addpath (pwd); savepath ();" diff --git a/tests/makeRawDataset_test.m b/tests/test_makeRawDataset.m similarity index 98% rename from tests/makeRawDataset_test.m rename to tests/test_makeRawDataset.m index 137a8353..a6346bfd 100644 --- a/tests/makeRawDataset_test.m +++ b/tests/test_makeRawDataset.m @@ -1,4 +1,4 @@ -function makeRawDataset_test() +function test_makeRawDataset() fprintf('\n\n--------------------------------------------------------------------\n\n'); From 9658b71128890516e7226ff6e1acd25e77bdf913 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 24 Jul 2020 17:37:12 +0200 Subject: [PATCH 21/26] change call to mh_linter --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 304e7d5c..dc3d41af 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,7 +37,7 @@ jobs: - stage: "Tests and linter" name: "Unit Tests" # names the first job script: octave $OCTFLAGS --eval "results = runTests; assert(all(~[results.Failed]))" - - script: cd .. && mh_style.py `pwd` + - script: cd .. && mh_style `pwd` name: "miss_hit linter" # names the second job - stage: "BIDS validator" name: "create and check dataset" # names the second job From faf11ef290bc7cf2c196340f3743375aecea8c10 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 24 Jul 2020 17:54:31 +0200 Subject: [PATCH 22/26] final touches --- .travis.yml | 7 ++-- README.md | 7 ++-- saveEventsFile.m | 66 ++++++++++++++++++++----------------- tests/test_makeRawDataset.m | 3 -- 4 files changed, 42 insertions(+), 41 deletions(-) diff --git a/.travis.yml b/.travis.yml index dc3d41af..3ddcd256 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,11 +19,8 @@ before_install: install: - # Install JSONio - #- travis_retry git clone git://github.com/gllmflndn/JSONio.git --depth 1 + # make octave file for JSONio - cd lib/JSONio; mkoctfile --mex jsonread.c jsmn.c -DJSMN_PARENT_LINKS; cd ../.. - #- octave $OCTFLAGS --eval "addpath (fullfile (pwd, 'JSONio')); savepath ();" - # Install BIDS-MATLAB - octave $OCTFLAGS --eval "addpath (pwd); savepath ();" # Install BIDS-Validator - sudo npm install -g bids-validator @@ -41,5 +38,5 @@ jobs: name: "miss_hit linter" # names the second job - stage: "BIDS validator" name: "create and check dataset" # names the second job - - script: octave $OCTFLAGS --eval "makeRawDataset_test" && bids-validator `pwd`/../output/rawdata/ --ignoreNiftiHeaders + script: octave $OCTFLAGS --eval "test_makeRawDataset" && bids-validator `pwd`/../output/rawdata/ --ignoreNiftiHeaders \ No newline at end of file diff --git a/README.md b/README.md index 1ebe012c..7ff419c5 100644 --- a/README.md +++ b/README.md @@ -127,16 +127,17 @@ logFile.extraColumns = {'Speed', 'is_Fixation'}; [cfg, expParameters] = createFilename(cfg, expParameters); -% dummy call to initialize the logFile variable -logFile = saveEventsFile('open', expParameters, logFile); +% initialize the logFile variable +[logFile] = saveEventsFile('init', expParameters, logFile); % set the real length we really want logFile.extraColumns.Speed.length = 12; -% actual inititalization +% open the file logFile = saveEventsFile('open', expParameters, logFile); ``` + ## Functions descriptions ### userInputs diff --git a/saveEventsFile.m b/saveEventsFile.m index 78dcefaa..aa8307ff 100644 --- a/saveEventsFile.m +++ b/saveEventsFile.m @@ -171,6 +171,8 @@ end function logFile = initializeFile(expParameters, logFile) + + createDataDictionary(expParameters, logFile); logFile = initializeExtraColumns(logFile); @@ -214,36 +216,6 @@ function printHeaderExtraColumns(logFile) end -function data = checkInput(data, expectedLength) - % 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 ischar(data) && isempty(data) || strcmp(data, ' ') - data = 'n/a'; - elseif isempty(data) - % important to not set this to n/a as we still need to check if this - % numeric valur has the right length and needs to be nan padded - data = nan; - end - - if islogical(data) && data - data = 'true'; - elseif islogical(data) && ~data - data = 'false'; - end - - if ~isempty(expectedLength) && isnumeric(data) && max(size(data)) < expectedLength - padding = expectedLength - max(size(data)); - data(end + 1:end + padding) = nan(1, padding); - end - -end - function logFile = checkExtracolumns(logFile, iEvent) % loops through the extra columns % if the field we are looking for does not exist or is empty in the @@ -277,6 +249,40 @@ function printHeaderExtraColumns(logFile) end +function data = checkInput(data, expectedLength) + % 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 + data = 'false'; + end + + + if ischar(data) && isempty(data) || strcmp(data, ' ') + data = 'n/a'; + elseif isempty(data) + % important to not set this to n/a as we still need to check if this + % numeric valur has the right length and needs to be nan padded + data = nan; + 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.') + end + +end + function printExtraColumns(logFile, iEvent) % loops through the extra columns and print them diff --git a/tests/test_makeRawDataset.m b/tests/test_makeRawDataset.m index a6346bfd..ce176a41 100644 --- a/tests/test_makeRawDataset.m +++ b/tests/test_makeRawDataset.m @@ -27,8 +27,6 @@ function test_makeRawDataset() cfg.testingDevice = 'mri'; - cfg.testingDevice = 'pc'; - logFile.extraColumns.Speed.length = 1; logFile.extraColumns.LHL24.length = 3; logFile.extraColumns.is_Fixation.length = 1; @@ -40,7 +38,6 @@ function test_makeRawDataset() % create the events file and header logFile = saveEventsFile('open', expParameters, logFile); - createDataDictionary(expParameters, logFile); createBoldJson(expParameters); createDatasetDescription(expParameters); From da855697e61e0d84793880523c9a6200a80800a9 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 24 Jul 2020 17:55:10 +0200 Subject: [PATCH 23/26] mh autofix --- saveEventsFile.m | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/saveEventsFile.m b/saveEventsFile.m index aa8307ff..4b0aa196 100644 --- a/saveEventsFile.m +++ b/saveEventsFile.m @@ -171,7 +171,7 @@ end function logFile = initializeFile(expParameters, logFile) - + createDataDictionary(expParameters, logFile); logFile = initializeExtraColumns(logFile); @@ -257,13 +257,12 @@ function printHeaderExtraColumns(logFile) if nargin < 2 expectedLength = []; end - + if islogical(data) && data data = 'true'; elseif islogical(data) && ~data data = 'false'; end - if ischar(data) && isempty(data) || strcmp(data, ' ') data = 'n/a'; @@ -278,7 +277,7 @@ function printHeaderExtraColumns(logFile) 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.') + warning('A field for this event is longer than expected. Truncating the extra values.'); end end From 4839a08031c7c4447bcf1f0303d58727d49819ab Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 24 Jul 2020 18:09:37 +0200 Subject: [PATCH 24/26] fix failing tests --- saveEventsFile.m | 4 ++-- tests/runTests.m | 9 +++++++++ tests/test_createBoldJson.m | 2 +- tests/test_createDataDictionary.m | 2 +- ...test_makeRawDataset.m => testmanual_makeRawDataset.m} | 0 5 files changed, 13 insertions(+), 4 deletions(-) rename tests/{test_makeRawDataset.m => testmanual_makeRawDataset.m} (100%) diff --git a/saveEventsFile.m b/saveEventsFile.m index 4b0aa196..7c9f0830 100644 --- a/saveEventsFile.m +++ b/saveEventsFile.m @@ -171,11 +171,11 @@ end function logFile = initializeFile(expParameters, logFile) + + logFile = initializeExtraColumns(logFile); createDataDictionary(expParameters, logFile); - logFile = initializeExtraColumns(logFile); - % Initialize txt logfiles and empty fields for the standard BIDS % event file logFile.fileID = fopen( ... diff --git a/tests/runTests.m b/tests/runTests.m index b53a104f..77ceecec 100644 --- a/tests/runTests.m +++ b/tests/runTests.m @@ -51,4 +51,13 @@ fprintf(['Totals (%d tests):\n\t%d Passed, %d Failed, %d Incomplete.\n' ... '\t%f seconds testing time.\n\n'], numel(results), nnz([results.Passed]), ... nnz([results.Failed]), nnz([results.Incomplete]), sum([results.Duration])); + for i = 1:numel(d) + status = 'Incomplete'; + if results(i).Passed + status = 'Passed'; + elseif results(i).Failed + status = 'Failed'; + end + fprintf('%s: %s\n', d(i).name(1:end - 2), status); + end end diff --git a/tests/test_createBoldJson.m b/tests/test_createBoldJson.m index 6ee9bb07..b5bd9130 100644 --- a/tests/test_createBoldJson.m +++ b/tests/test_createBoldJson.m @@ -14,7 +14,7 @@ function test_createBoldJson() [cfg, expParameters] = createFilename(cfg, expParameters); %#ok<*ASGLU> - logFile = saveEventsFile('open', expParameters); %#ok<*NASGU> + logFile = saveEventsFile('init', expParameters); %#ok<*NASGU> createBoldJson(expParameters); diff --git a/tests/test_createDataDictionary.m b/tests/test_createDataDictionary.m index 636371de..d5875706 100644 --- a/tests/test_createDataDictionary.m +++ b/tests/test_createDataDictionary.m @@ -18,7 +18,7 @@ function test_createDataDictionary() logFile.extraColumns.Speed.length = 1; logFile.extraColumns.LHL24.length = 3; - logFile = saveEventsFile('open', expParameters, logFile); + logFile = saveEventsFile('init', expParameters, logFile); createDataDictionary(expParameters, logFile); diff --git a/tests/test_makeRawDataset.m b/tests/testmanual_makeRawDataset.m similarity index 100% rename from tests/test_makeRawDataset.m rename to tests/testmanual_makeRawDataset.m From b608535f2d5f66e947f6761b96c63de691165669 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 24 Jul 2020 18:16:23 +0200 Subject: [PATCH 25/26] update travis.yml - run linter last --- .travis.yml | 12 +++++++----- saveEventsFile.m | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3ddcd256..b9ca86df 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,12 +31,14 @@ before_script: jobs: include: - - stage: "Tests and linter" - name: "Unit Tests" # names the first job + - stage: "Tests" + name: "Unit and integration Tests" script: octave $OCTFLAGS --eval "results = runTests; assert(all(~[results.Failed]))" - - script: cd .. && mh_style `pwd` - name: "miss_hit linter" # names the second job - stage: "BIDS validator" - name: "create and check dataset" # names the second job + name: "Create and check dataset" script: octave $OCTFLAGS --eval "test_makeRawDataset" && bids-validator `pwd`/../output/rawdata/ --ignoreNiftiHeaders + - stage: "Linter" + name: "miss_hit" + script: cd .. && mh_style `pwd` + \ No newline at end of file diff --git a/saveEventsFile.m b/saveEventsFile.m index 7c9f0830..278d0aa5 100644 --- a/saveEventsFile.m +++ b/saveEventsFile.m @@ -171,7 +171,7 @@ end function logFile = initializeFile(expParameters, logFile) - + logFile = initializeExtraColumns(logFile); createDataDictionary(expParameters, logFile); From b227d420fefb645998941dc9798d13eb820103cb Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 24 Jul 2020 18:42:56 +0200 Subject: [PATCH 26/26] fix typo --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b9ca86df..0cdf80af 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 "test_makeRawDataset" && bids-validator `pwd`/../output/rawdata/ --ignoreNiftiHeaders + script: octave $OCTFLAGS --eval "testmanual_makeRawDataset" && bids-validator `pwd`/../output/rawdata/ --ignoreNiftiHeaders - stage: "Linter" name: "miss_hit" script: cd .. && mh_style `pwd`