Skip to content

Commit 4077957

Browse files
authored
Merge pull request #57 from CerenB/master
cfg conversion
2 parents ed7577a + ca7541d commit 4077957

30 files changed

+753
-464
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
script: octave $OCTFLAGS --eval "results = runTests; assert(all(~[results.Failed]))"
3737
- stage: "BIDS validator"
3838
name: "Create and check dataset"
39-
script: octave $OCTFLAGS --eval "testmanual_makeRawDataset" && bids-validator `pwd`/../output/rawdata/ --ignoreNiftiHeaders
39+
script: cd manualTests && octave $OCTFLAGS --eval "test_makeRawDataset" && bids-validator `pwd`/output/rawdata/ --ignoreNiftiHeaders
4040
- stage: "Linter"
4141
name: "miss_hit"
4242
script: cd .. && mh_style `pwd`

checkCFG.m

Lines changed: 150 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,110 +1,188 @@
1-
function [cfg, expParameters] = checkCFG(cfg, expParameters)
1+
function cfg = checkCFG(cfg)
22
% check that we have all the fields that we need in the experiment parameters
3+
% reuses a lot of code from the BIDS starter kit
34

45
checkCppBidsDependencies();
56

67
if nargin < 1 || isempty(cfg)
78
cfg = struct();
89
end
9-
if nargin < 2 || isempty(expParameters)
10-
expParameters = struct();
11-
end
1210

13-
%% set the expParameters defaults
11+
%% set the cfg defaults
1412

1513
fieldsToSet.verbose = false;
16-
fieldsToSet.outputDir = fullfile( ...
14+
15+
fieldsToSet.fileName.task = '';
16+
fieldsToSet.fileName.zeroPadding = 3;
17+
fieldsToSet.fileName.dateFormat = 'yyyymmddHHMM';
18+
19+
fieldsToSet.dir.output = fullfile( ...
1720
fileparts(mfilename('fullpath')), ...
1821
'..', ...
1922
'output');
2023

21-
fieldsToSet = mriDefaults(fieldsToSet);
24+
fieldsToSet.subject.askGrpSess = [true true];
25+
fieldsToSet.subject.sessionNb = 1; % in case no session was provided
26+
fieldsToSet.subject.subjectGrp = ''; % in case no group was provided
2227

23-
fieldsToSet.subjectGrp = ''; % in case no group was provided
24-
fieldsToSet.sessionNb = 1; % in case no session was provided
25-
fieldsToSet.askGrpSess = [true true];
28+
fieldsToSet.testingDevice = 'pc';
29+
30+
fieldsToSet.eyeTracker = struct();
2631

27-
expParameters = setDefaultFields(expParameters, fieldsToSet);
32+
fieldsToSet.eyeTracker.do = false;
33+
34+
fieldsToSet = mriDefaults(fieldsToSet);
2835

2936
%% BIDS
30-
clear fieldsToSet;
31-
fieldsToSet.bids = struct();
32-
expParameters = setDefaultFields(expParameters, fieldsToSet);
3337

34-
clear fieldsToSet;
35-
fieldsToSet.MRI = struct();
36-
fieldsToSet.datasetDescription = struct();
37-
expParameters.bids = setDefaultFields(expParameters.bids, fieldsToSet);
38+
fieldsToSet = datasetDescriptionDefaults(fieldsToSet);
39+
fieldsToSet = mriJsonDefaults(fieldsToSet);
40+
fieldsToSet = megJsonDefaults(fieldsToSet);
3841

39-
clear fieldsToSet;
40-
fieldsToSet = datasetDescriptionDefaults();
42+
fieldsToSet = transferInfoToBids(fieldsToSet, cfg);
4143

42-
expParameters.bids.datasetDescription = ...
43-
setDefaultFields(expParameters.bids.datasetDescription, fieldsToSet);
44+
cfg = setDefaultFields(cfg, fieldsToSet);
4445

45-
clear fieldsToSet;
46-
fieldsToSet = mriJsonDefaults();
47-
if isfield(expParameters, 'task')
48-
fieldsToSet.TaskName = expParameters.task;
49-
end
46+
end
5047

51-
expParameters.bids.MRI = ...
52-
setDefaultFields(expParameters.bids.MRI, fieldsToSet);
48+
function fieldsToSet = mriDefaults(fieldsToSet)
5349

54-
% sort fields alphabetically
55-
expParameters = orderfields(expParameters);
50+
% for file naming and JSON
51+
fieldsToSet.mri.contrastEnhancement = [];
52+
fieldsToSet.mri.phaseEncodingDirection = [];
53+
fieldsToSet.mri.reconstruction = [];
54+
fieldsToSet.mri.echo = [];
55+
fieldsToSet.mri.acquisition = [];
56+
fieldsToSet.mri.repetitionTime = [];
5657

57-
%% set the cfg defaults
58+
fieldsToSet.mri = orderfields(fieldsToSet.mri);
5859

59-
clear fieldsToSet;
60-
fieldsToSet.verbose = false;
61-
fieldsToSet.testingDevice = 'pc';
62-
fieldsToSet.eyeTracker = false;
60+
end
6361

64-
cfg = setDefaultFields(cfg, fieldsToSet);
62+
function fieldsToSet = datasetDescriptionDefaults(fieldsToSet)
6563

66-
% sort fields alphabetically
67-
cfg = orderfields(cfg);
64+
% REQUIRED name of the dataset
65+
fieldsToSet.bids.datasetDescription.Name = '';
6866

69-
end
67+
% REQUIRED The version of the BIDS standard that was used
68+
fieldsToSet.bids.datasetDescription.BIDSVersion = '';
7069

71-
function fieldsToSet = mriDefaults(fieldsToSet)
70+
% RECOMMENDED
71+
% what license is this dataset distributed under? The
72+
% use of license name abbreviations is suggested for specifying a license.
73+
% A list of common licenses with suggested abbreviations can be found in appendix III.
74+
fieldsToSet.bids.datasetDescription.License = '';
75+
76+
% RECOMMENDED List of individuals who contributed to the
77+
% creation/curation of the dataset
78+
fieldsToSet.bids.datasetDescription.Authors = {''};
79+
80+
% RECOMMENDED who should be acknowledge in helping to collect the data
81+
fieldsToSet.bids.datasetDescription.Acknowledgements = '';
7282

73-
% for file naming
74-
fieldsToSet.MRI.ce = [];
75-
fieldsToSet.MRI.dir = []; % phase encoding direction of acquisition for fMRI
76-
fieldsToSet.MRI.rec = []; % reconstruction of fMRI images
77-
fieldsToSet.MRI.echo = []; % echo fMRI images
78-
fieldsToSet.MRI.acq = []; % acquisition of fMRI images
83+
% RECOMMENDED Instructions how researchers using this
84+
% dataset should acknowledge the original authors. This field can also be used
85+
% to define a publication that should be cited in publications that use the
86+
% dataset.
87+
fieldsToSet.bids.datasetDescription.HowToAcknowledge = '';
88+
89+
% RECOMMENDED sources of funding (grant numbers)
90+
fieldsToSet.bids.datasetDescription.Funding = {''};
91+
92+
% RECOMMENDED a list of references to
93+
% publication that contain information on the dataset, or links.
94+
fieldsToSet.bids.datasetDescription.ReferencesAndLinks = {''};
95+
96+
% RECOMMENDED the Document Object Identifier of the dataset
97+
% (not the corresponding paper).
98+
fieldsToSet.bids.datasetDescription.DatasetDOI = '';
99+
100+
% sort fields alphabetically
101+
fieldsToSet.bids.datasetDescription = orderfields(fieldsToSet.bids.datasetDescription);
79102

80103
end
81104

82-
function fieldsToSet = datasetDescriptionDefaults()
83-
% required
84-
fieldsToSet.Name = '';
85-
fieldsToSet.BIDSVersion = '';
86-
% recommended
87-
fieldsToSet.License = '';
88-
fieldsToSet.Authors = {''};
89-
fieldsToSet.Acknowledgements = '';
90-
fieldsToSet.HowToAcknowledge = '';
91-
fieldsToSet.Funding = {''};
92-
fieldsToSet.ReferencesAndLinks = {''};
93-
fieldsToSet.DatasetDOI = '';
105+
function fieldsToSet = mriJsonDefaults(fieldsToSet)
106+
% for json for funcfional MRI data
107+
108+
% REQUIRED The time in seconds between the beginning of an acquisition of
109+
% one volume and the beginning of acquisition of the volume following it
110+
% (TR). Please note that this definition includes time between scans
111+
% (when no data has been acquired) in case of sparse acquisition schemes.
112+
% This value needs to be consistent with the pixdim[4] field
113+
% (after accounting for units stored in xyzt_units field) in the NIfTI header
114+
fieldsToSet.bids.mri.RepetitionTime = [];
115+
116+
% REQUIRED for sparse sequences that do not have the DelayTime field set.
117+
% This parameter is required for sparse sequences. In addition without this
118+
% parameter slice time correction will not be possible.
119+
%
120+
% In addition without this parameter slice time correction will not be possible.
121+
% The time at which each slice was acquired within each volume (frame) of the acquisition.
122+
% The time at which each slice was acquired during the acquisition. Slice
123+
% timing is not slice order - it describes the time (sec) of each slice
124+
% acquisition in relation to the beginning of volume acquisition. It is
125+
% described using a list of times (in JSON format) referring to the acquisition
126+
% time for each slice. The list goes through slices along the slice axis in the
127+
% slice encoding dimension.
128+
fieldsToSet.bids.mri.SliceTiming = [];
129+
130+
% REQUIRED Name of the task (for resting state use the "rest" prefix). No two tasks
131+
% should have the same name. Task label is derived from this field by
132+
% removing all non alphanumeric ([a-zA-Z0-9]) characters.
133+
fieldsToSet.bids.mri.TaskName = [];
134+
135+
% RECOMMENDED Text of the instructions given to participants before the scan.
136+
% This is especially important in context of resting state fMRI and
137+
% distinguishing between eyes open and eyes closed paradigms.
138+
fieldsToSet.bids.mri.Instructions = '';
139+
140+
% RECOMMENDED Longer description of the task.
141+
fieldsToSet.bids.mri.TaskDescription = '';
142+
143+
% fieldsToSet.PhaseEncodingDirection = [];
144+
% fieldsToSet.EffectiveEchoSpacing = [];
145+
% fieldsToSet.EchoTime = [];
146+
147+
fieldsToSet.bids.mri = orderfields(fieldsToSet.bids.mri);
148+
94149
end
95150

96-
function fieldsToSet = mriJsonDefaults()
97-
98-
% for json for funcfional data
99-
% required
100-
fieldsToSet.RepetitionTime = [];
101-
fieldsToSet.SliceTiming = [];
102-
fieldsToSet.TaskName = [];
103-
% fieldsToSet.PhaseEncodingDirection = [];
104-
% fieldsToSet.EffectiveEchoSpacing = [];
105-
% fieldsToSet.EchoTime = [];
106-
% recommended
107-
fieldsToSet.Instructions = [];
108-
fieldsToSet.TaskDescription = [];
151+
function fieldsToSet = megJsonDefaults(fieldsToSet)
152+
% for json for MEG data
153+
154+
% REQUIRED Name of the task (for resting state use the "rest" prefix). No two tasks
155+
% should have the same name. Task label is derived from this field by
156+
% removing all non alphanumeric ([a-zA-Z0-9]) characters.
157+
fieldsToSet.bids.meg.TaskName = [];
158+
159+
% REQUIRED Sampling frequency
160+
fieldsToSet.bids.meg.SamplingFrequency = [];
161+
162+
% REQUIRED Frequency (in Hz) of the power grid at the geographical location of
163+
% the MEG instrument (i.e. 50 or 60):
164+
fieldsToSet.bids.meg.PowerLineFrequency = [];
165+
166+
% REQUIRED Position of the dewar during the MEG scan: "upright", "supine" or
167+
% "degrees" of angle from vertical: for example on CTF systems,
168+
% upright=15°, supine = 90°:
169+
fieldsToSet.bids.meg.DewarPosition = [];
170+
171+
% REQUIRED List of temporal and/or spatial software filters applied, or ideally
172+
% key:value pairs of pre-applied software filters and their parameter
173+
% values: e.g., {"SSS": {"frame": "head", "badlimit": 7}},
174+
% {"SpatialCompensation": {"GradientOrder": Order of the gradient
175+
% compensation}}. Write "n/a" if no software filters applied.
176+
fieldsToSet.bids.meg.SoftwareFilters = [];
177+
178+
% REQUIRED Boolean ("true" or "false") value indicating whether anatomical
179+
% landmark points (i.e. fiducials) are contained within this recording.
180+
fieldsToSet.bids.meg.DigitizedLandmarks = [];
181+
182+
% REQUIRED Boolean ("true" or "false") value indicating whether head points
183+
% outlining the scalp/face surface are contained within this recording
184+
fieldsToSet.bids.meg.DigitizedHeadPoints = [];
185+
186+
fieldsToSet.bids.meg = orderfields(fieldsToSet.bids.meg);
109187

110188
end

checkCppBidsDependencies.m

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
function checkCppBidsDependencies
22

33
pth = fileparts(mfilename('fullpath'));
4-
5-
checkSubmodule(fullfile(pth, 'lib', 'JSONio'))
6-
checkSubmodule(fullfile(pth, 'lib', 'bids-matlab'))
7-
4+
5+
checkSubmodule(fullfile(pth, 'lib', 'JSONio'));
6+
checkSubmodule(fullfile(pth, 'lib', 'bids-matlab'));
7+
88
addpath(fullfile(pth, 'lib', 'utils'));
99
addpath(fullfile(pth, 'subfun'));
10-
10+
1111
printCreditsCppBids();
1212

1313
end

convertSourceToRaw.m

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
function convertSourceToRaw(expParameters)
1+
function convertSourceToRaw(cfg)
22

3-
sourceDir = fullfile(expParameters.outputDir, 'source');
4-
rawDir = fullfile(expParameters.outputDir, 'rawdata');
3+
sourceDir = fullfile(cfg.dir.output, 'source');
4+
rawDir = fullfile(cfg.dir.output, 'rawdata');
55

66
% add dummy readme and change file
7-
copyfile(fullfile('..', 'dummyData', 'README'), sourceDir);
8-
copyfile(fullfile('..', 'dummyData', 'CHANGES'), sourceDir);
7+
copyfile(fullfile( ...
8+
fileparts(mfilename('fullpath')), 'dummyData', 'README'), ...
9+
sourceDir);
10+
copyfile(fullfile( ...
11+
fileparts(mfilename('fullpath')), 'dummyData', 'CHANGES'), ...
12+
sourceDir);
913

1014
copyfile(sourceDir, rawDir);
1115

createBoldJson.m

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
function createBoldJson(expParameters)
1+
function createBoldJson(cfg)
22

33
opts.Indent = ' ';
44

5-
fileName = strrep(expParameters.fileName.events, '_events', '_bold');
5+
fileName = strrep(cfg.fileName.events, '_events', '_bold');
66
fileName = strrep(fileName, '.tsv', '.json');
77

88
fileName = fullfile( ...
9-
expParameters.subjectOutputDir, ...
10-
expParameters.modality, ...
9+
cfg.dir.outputSubject, ...
10+
cfg.fileName.modality, ...
1111
fileName);
1212

13-
jsonContent = expParameters.bids.MRI;
13+
jsonContent = cfg.bids.mri;
1414

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

createDataDictionary.m

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
function createDataDictionary(expParameters, logFile)
1+
function createDataDictionary(cfg, logFile)
22

33
opts.Indent = ' ';
44

5-
fileName = strrep(expParameters.fileName.events, '.tsv', '.json');
5+
fileName = strrep(cfg.fileName.events, '.tsv', '.json');
66

77
fileName = fullfile( ...
8-
expParameters.subjectOutputDir, ...
9-
expParameters.modality, ...
8+
cfg.dir.outputSubject, ...
9+
cfg.fileName.modality, ...
1010
fileName);
1111

1212
jsonContent = struct( ...

createDatasetDescription.m

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
function createDatasetDescription(expParameters)
1+
function createDatasetDescription(cfg)
22

33
opts.Indent = ' ';
44

55
fileName = fullfile( ...
6-
expParameters.outputDir, 'source', ...
6+
cfg.dir.output, 'source', ...
77
'dataset_description.json');
88

9-
jsonContent = expParameters.bids.datasetDescription;
9+
jsonContent = cfg.bids.datasetDescription;
1010

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

0 commit comments

Comments
 (0)