Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
script: octave $OCTFLAGS --eval "results = runTests; assert(all(~[results.Failed]))"
- stage: "BIDS validator"
name: "Create and check dataset"
script: octave $OCTFLAGS --eval "testmanual_makeRawDataset" && bids-validator `pwd`/../output/rawdata/ --ignoreNiftiHeaders
script: cd manualTests && octave $OCTFLAGS --eval "test_makeRawDataset" && bids-validator `pwd`/output/rawdata/ --ignoreNiftiHeaders
- stage: "Linter"
name: "miss_hit"
script: cd .. && mh_style `pwd`
Expand Down
222 changes: 150 additions & 72 deletions checkCFG.m
Original file line number Diff line number Diff line change
@@ -1,110 +1,188 @@
function [cfg, expParameters] = checkCFG(cfg, expParameters)
function cfg = checkCFG(cfg)
% check that we have all the fields that we need in the experiment parameters
% reuses a lot of code from the BIDS starter kit

checkCppBidsDependencies();

if nargin < 1 || isempty(cfg)
cfg = struct();
end
if nargin < 2 || isempty(expParameters)
expParameters = struct();
end

%% set the expParameters defaults
%% set the cfg defaults

fieldsToSet.verbose = false;
fieldsToSet.outputDir = fullfile( ...

fieldsToSet.fileName.task = '';
fieldsToSet.fileName.zeroPadding = 3;
fieldsToSet.fileName.dateFormat = 'yyyymmddHHMM';

fieldsToSet.dir.output = fullfile( ...
fileparts(mfilename('fullpath')), ...
'..', ...
'output');

fieldsToSet = mriDefaults(fieldsToSet);
fieldsToSet.subject.askGrpSess = [true true];
fieldsToSet.subject.sessionNb = 1; % in case no session was provided
fieldsToSet.subject.subjectGrp = ''; % in case no group was provided

fieldsToSet.subjectGrp = ''; % in case no group was provided
fieldsToSet.sessionNb = 1; % in case no session was provided
fieldsToSet.askGrpSess = [true true];
fieldsToSet.testingDevice = 'pc';

fieldsToSet.eyeTracker = struct();

expParameters = setDefaultFields(expParameters, fieldsToSet);
fieldsToSet.eyeTracker.do = false;

fieldsToSet = mriDefaults(fieldsToSet);

%% BIDS
clear fieldsToSet;
fieldsToSet.bids = struct();
expParameters = setDefaultFields(expParameters, fieldsToSet);

clear fieldsToSet;
fieldsToSet.MRI = struct();
fieldsToSet.datasetDescription = struct();
expParameters.bids = setDefaultFields(expParameters.bids, fieldsToSet);
fieldsToSet = datasetDescriptionDefaults(fieldsToSet);
fieldsToSet = mriJsonDefaults(fieldsToSet);
fieldsToSet = megJsonDefaults(fieldsToSet);

clear fieldsToSet;
fieldsToSet = datasetDescriptionDefaults();
fieldsToSet = transferInfoToBids(fieldsToSet, cfg);

expParameters.bids.datasetDescription = ...
setDefaultFields(expParameters.bids.datasetDescription, fieldsToSet);
cfg = setDefaultFields(cfg, fieldsToSet);

clear fieldsToSet;
fieldsToSet = mriJsonDefaults();
if isfield(expParameters, 'task')
fieldsToSet.TaskName = expParameters.task;
end
end

expParameters.bids.MRI = ...
setDefaultFields(expParameters.bids.MRI, fieldsToSet);
function fieldsToSet = mriDefaults(fieldsToSet)

% sort fields alphabetically
expParameters = orderfields(expParameters);
% for file naming and JSON
fieldsToSet.mri.contrastEnhancement = [];
fieldsToSet.mri.phaseEncodingDirection = [];
fieldsToSet.mri.reconstruction = [];
fieldsToSet.mri.echo = [];
fieldsToSet.mri.acquisition = [];
fieldsToSet.mri.repetitionTime = [];

%% set the cfg defaults
fieldsToSet.mri = orderfields(fieldsToSet.mri);

clear fieldsToSet;
fieldsToSet.verbose = false;
fieldsToSet.testingDevice = 'pc';
fieldsToSet.eyeTracker = false;
end

cfg = setDefaultFields(cfg, fieldsToSet);
function fieldsToSet = datasetDescriptionDefaults(fieldsToSet)

% sort fields alphabetically
cfg = orderfields(cfg);
% REQUIRED name of the dataset
fieldsToSet.bids.datasetDescription.Name = '';

end
% REQUIRED The version of the BIDS standard that was used
fieldsToSet.bids.datasetDescription.BIDSVersion = '';

function fieldsToSet = mriDefaults(fieldsToSet)
% RECOMMENDED
% what license is this dataset distributed under? The
% use of license name abbreviations is suggested for specifying a license.
% A list of common licenses with suggested abbreviations can be found in appendix III.
fieldsToSet.bids.datasetDescription.License = '';

% RECOMMENDED List of individuals who contributed to the
% creation/curation of the dataset
fieldsToSet.bids.datasetDescription.Authors = {''};

% RECOMMENDED who should be acknowledge in helping to collect the data
fieldsToSet.bids.datasetDescription.Acknowledgements = '';

% 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
% RECOMMENDED Instructions how researchers using this
% dataset should acknowledge the original authors. This field can also be used
% to define a publication that should be cited in publications that use the
% dataset.
fieldsToSet.bids.datasetDescription.HowToAcknowledge = '';

% RECOMMENDED sources of funding (grant numbers)
fieldsToSet.bids.datasetDescription.Funding = {''};

% RECOMMENDED a list of references to
% publication that contain information on the dataset, or links.
fieldsToSet.bids.datasetDescription.ReferencesAndLinks = {''};

% RECOMMENDED the Document Object Identifier of the dataset
% (not the corresponding paper).
fieldsToSet.bids.datasetDescription.DatasetDOI = '';

% sort fields alphabetically
fieldsToSet.bids.datasetDescription = orderfields(fieldsToSet.bids.datasetDescription);

end

function fieldsToSet = datasetDescriptionDefaults()
% required
fieldsToSet.Name = '';
fieldsToSet.BIDSVersion = '';
% recommended
fieldsToSet.License = '';
fieldsToSet.Authors = {''};
fieldsToSet.Acknowledgements = '';
fieldsToSet.HowToAcknowledge = '';
fieldsToSet.Funding = {''};
fieldsToSet.ReferencesAndLinks = {''};
fieldsToSet.DatasetDOI = '';
function fieldsToSet = mriJsonDefaults(fieldsToSet)
% for json for funcfional MRI data

% REQUIRED The time in seconds between the beginning of an acquisition of
% one volume and the beginning of acquisition of the volume following it
% (TR). Please note that this definition includes time between scans
% (when no data has been acquired) in case of sparse acquisition schemes.
% This value needs to be consistent with the pixdim[4] field
% (after accounting for units stored in xyzt_units field) in the NIfTI header
fieldsToSet.bids.mri.RepetitionTime = [];

% REQUIRED for sparse sequences that do not have the DelayTime field set.
% This parameter is required for sparse sequences. In addition without this
% parameter slice time correction will not be possible.
%
% In addition without this parameter slice time correction will not be possible.
% The time at which each slice was acquired within each volume (frame) of the acquisition.
% The time at which each slice was acquired during the acquisition. Slice
% timing is not slice order - it describes the time (sec) of each slice
% acquisition in relation to the beginning of volume acquisition. It is
% described using a list of times (in JSON format) referring to the acquisition
% time for each slice. The list goes through slices along the slice axis in the
% slice encoding dimension.
fieldsToSet.bids.mri.SliceTiming = [];

% REQUIRED Name of the task (for resting state use the "rest" prefix). No two tasks
% should have the same name. Task label is derived from this field by
% removing all non alphanumeric ([a-zA-Z0-9]) characters.
fieldsToSet.bids.mri.TaskName = [];

% RECOMMENDED Text of the instructions given to participants before the scan.
% This is especially important in context of resting state fMRI and
% distinguishing between eyes open and eyes closed paradigms.
fieldsToSet.bids.mri.Instructions = '';

% RECOMMENDED Longer description of the task.
fieldsToSet.bids.mri.TaskDescription = '';

% fieldsToSet.PhaseEncodingDirection = [];
% fieldsToSet.EffectiveEchoSpacing = [];
% fieldsToSet.EchoTime = [];

fieldsToSet.bids.mri = orderfields(fieldsToSet.bids.mri);

end

function fieldsToSet = mriJsonDefaults()

% for json for funcfional data
% required
fieldsToSet.RepetitionTime = [];
fieldsToSet.SliceTiming = [];
fieldsToSet.TaskName = [];
% fieldsToSet.PhaseEncodingDirection = [];
% fieldsToSet.EffectiveEchoSpacing = [];
% fieldsToSet.EchoTime = [];
% recommended
fieldsToSet.Instructions = [];
fieldsToSet.TaskDescription = [];
function fieldsToSet = megJsonDefaults(fieldsToSet)
% for json for MEG data

% REQUIRED Name of the task (for resting state use the "rest" prefix). No two tasks
% should have the same name. Task label is derived from this field by
% removing all non alphanumeric ([a-zA-Z0-9]) characters.
fieldsToSet.bids.meg.TaskName = [];

% REQUIRED Sampling frequency
fieldsToSet.bids.meg.SamplingFrequency = [];

% REQUIRED Frequency (in Hz) of the power grid at the geographical location of
% the MEG instrument (i.e. 50 or 60):
fieldsToSet.bids.meg.PowerLineFrequency = [];

% REQUIRED Position of the dewar during the MEG scan: "upright", "supine" or
% "degrees" of angle from vertical: for example on CTF systems,
% upright=15°, supine = 90°:
fieldsToSet.bids.meg.DewarPosition = [];

% REQUIRED List of temporal and/or spatial software filters applied, or ideally
% key:value pairs of pre-applied software filters and their parameter
% values: e.g., {"SSS": {"frame": "head", "badlimit": 7}},
% {"SpatialCompensation": {"GradientOrder": Order of the gradient
% compensation}}. Write "n/a" if no software filters applied.
fieldsToSet.bids.meg.SoftwareFilters = [];

% REQUIRED Boolean ("true" or "false") value indicating whether anatomical
% landmark points (i.e. fiducials) are contained within this recording.
fieldsToSet.bids.meg.DigitizedLandmarks = [];

% REQUIRED Boolean ("true" or "false") value indicating whether head points
% outlining the scalp/face surface are contained within this recording
fieldsToSet.bids.meg.DigitizedHeadPoints = [];

fieldsToSet.bids.meg = orderfields(fieldsToSet.bids.meg);

end
10 changes: 5 additions & 5 deletions checkCppBidsDependencies.m
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
function checkCppBidsDependencies

pth = fileparts(mfilename('fullpath'));
checkSubmodule(fullfile(pth, 'lib', 'JSONio'))
checkSubmodule(fullfile(pth, 'lib', 'bids-matlab'))

checkSubmodule(fullfile(pth, 'lib', 'JSONio'));
checkSubmodule(fullfile(pth, 'lib', 'bids-matlab'));

addpath(fullfile(pth, 'lib', 'utils'));
addpath(fullfile(pth, 'subfun'));

printCreditsCppBids();

end
Expand Down
14 changes: 9 additions & 5 deletions convertSourceToRaw.m
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
function convertSourceToRaw(expParameters)
function convertSourceToRaw(cfg)

sourceDir = fullfile(expParameters.outputDir, 'source');
rawDir = fullfile(expParameters.outputDir, 'rawdata');
sourceDir = fullfile(cfg.dir.output, 'source');
rawDir = fullfile(cfg.dir.output, 'rawdata');

% add dummy readme and change file
copyfile(fullfile('..', 'dummyData', 'README'), sourceDir);
copyfile(fullfile('..', 'dummyData', 'CHANGES'), sourceDir);
copyfile(fullfile( ...
fileparts(mfilename('fullpath')), 'dummyData', 'README'), ...
sourceDir);
copyfile(fullfile( ...
fileparts(mfilename('fullpath')), 'dummyData', 'CHANGES'), ...
sourceDir);

copyfile(sourceDir, rawDir);

Expand Down
10 changes: 5 additions & 5 deletions createBoldJson.m
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
function createBoldJson(expParameters)
function createBoldJson(cfg)

opts.Indent = ' ';

fileName = strrep(expParameters.fileName.events, '_events', '_bold');
fileName = strrep(cfg.fileName.events, '_events', '_bold');
fileName = strrep(fileName, '.tsv', '.json');

fileName = fullfile( ...
expParameters.subjectOutputDir, ...
expParameters.modality, ...
cfg.dir.outputSubject, ...
cfg.fileName.modality, ...
fileName);

jsonContent = expParameters.bids.MRI;
jsonContent = cfg.bids.mri;

bids.util.jsonencode(fileName, jsonContent, opts);

Expand Down
8 changes: 4 additions & 4 deletions createDataDictionary.m
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
function createDataDictionary(expParameters, logFile)
function createDataDictionary(cfg, logFile)

opts.Indent = ' ';

fileName = strrep(expParameters.fileName.events, '.tsv', '.json');
fileName = strrep(cfg.fileName.events, '.tsv', '.json');

fileName = fullfile( ...
expParameters.subjectOutputDir, ...
expParameters.modality, ...
cfg.dir.outputSubject, ...
cfg.fileName.modality, ...
fileName);

jsonContent = struct( ...
Expand Down
6 changes: 3 additions & 3 deletions createDatasetDescription.m
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
function createDatasetDescription(expParameters)
function createDatasetDescription(cfg)

opts.Indent = ' ';

fileName = fullfile( ...
expParameters.outputDir, 'source', ...
cfg.dir.output, 'source', ...
'dataset_description.json');

jsonContent = expParameters.bids.datasetDescription;
jsonContent = cfg.bids.datasetDescription;

bids.util.jsonencode(fileName, jsonContent, opts);

Expand Down
Loading