-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathcreateDefaultStatsModel.m
164 lines (141 loc) · 4.76 KB
/
createDefaultStatsModel.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
function opt = createDefaultStatsModel(BIDS, opt, ignore)
%
% Creates a default model json file for a BIDS dataset
%
% USAGE::
%
% opt = createDefaultStatsModel(BIDS, opt)
%
% :param BIDS: dataset layout.
% See: bids.layout, getData.
% :type BIDS: struct or path
%
% :param opt: Options chosen for the analysis.
% See :func:`checkOptions`.
% :type opt: structure
%
% :param ignore: Optional. Cell string that can contain:
% - ``"Transformations"``
% - ``"Contrasts"``
% - ``"Dataset"``
% Can be used to avoid generating certain objects of the BIDS stats model.
% :type ignore: cellstr
%
% :return: opt
%
% Outputs a model file in the current directory::
%
% fullfile(pwd, 'models', ['model-default' opt.taskName '_smdl.json']);
%
% This model has 3 "Nodes" in that order
%
% - Run level
%
% - will create a GLM with a design matrix that includes all
% all the possible type of trial_types that exist across
% all subjects and runs for the task specified in ``opt``,
% as well as the realignment parameters.
%
% - use ``DummyContrasts`` to generate contrasts for each trial_type
% for each run. This can be useful to run MVPA analysis on the beta
% images of each run.
%
% - Subject level
%
% - will create a GLM with a design matrix that includes all
% all the possible type of trial_types that exist across
% all subjects and runs for the task specified in ``opt``,
% as well as the realignment parameters.
%
% - use ``DummyContrasts`` to generate contrasts for all each trial_type
% across runs
%
% - Dataset level
%
% - use ``DummyContrasts`` to generate contrasts for each trial_type
% for at the group level.
%
% EXAMPLE::
%
% opt.taskName = 'myFascinatingTask';
% opt.dir.raw = fullfile(pwd, 'data', 'raw');
% opt = checkOptions(opt);
%
% [BIDS, opt] = getData(opt, opt.dir.raw);
%
% createDefaultStatsModel(BIDS, opt);
%
% (C) Copyright 2020 bidspm developers
DEFAULT_CONFOUNDS = {'trans_?'
'rot_?'
'non_steady_state_outlier*'
'motion_outlier*'};
if nargin < 3
ignore = {};
end
bm = BidsModel();
bm = bm.default(BIDS, opt.taskName);
% add realign parameters
for iRealignParam = 1:numel(DEFAULT_CONFOUNDS)
bm.Nodes{1}.Model.X{end + 1} = DEFAULT_CONFOUNDS{iRealignParam};
end
bm.Nodes{1}.Model.Software = struct('SPM', struct('SerialCorrelation', 'FAST', ...
'InclusiveMaskingThreshold', 0.8));
bm.Nodes{1}.Model.HRF.Model = 'spm';
% remove session level
[~, idx] = bm.get_nodes('Level', 'session');
if ~isempty(idx)
bm.Nodes(idx) = [];
end
% simplify higher levels
levelsToUpdate = {'subject', 'dataset'};
for i = 1:numel(levelsToUpdate)
[~, idx] = bm.get_nodes('Level', levelsToUpdate{i});
bm.Nodes{idx}.Model.X = {1};
if strcmp(levelsToUpdate{i}, 'subject')
bm.Nodes{idx}.GroupBy = {'subject', 'contrast'};
elseif strcmp(levelsToUpdate{i}, 'dataset')
bm.Nodes{idx}.GroupBy = {'contrast'};
end
bm.Nodes{idx} = rmfield(bm.Nodes{idx}, 'Contrasts');
bm.Nodes{idx}.DummyContrasts = rmfield(bm.Nodes{idx}.DummyContrasts, 'Contrasts');
bm.Nodes{idx}.Model = rmfield(bm.Nodes{idx}.Model, 'Software');
bm.Nodes{idx}.Model = rmfield(bm.Nodes{idx}.Model, 'Options');
end
if ismember('transformations', lower(ignore))
bm.Nodes{1} = rmfield(bm.Nodes{1}, 'Transformations');
end
if ismember('contrasts', lower(ignore))
bm.Nodes{1} = rmfield(bm.Nodes{1}, 'Contrasts');
end
if ismember('dataset', lower(ignore))
tmp = bm;
for i = 1:numel(tmp.Nodes)
if strcmpi(tmp.Nodes{i}.Level, 'dataset')
bm.Nodes(i) = [];
end
end
clear tmp;
end
for i = 1:numel(bm.Edges)
bm.Edges(1) = [];
end
bm = bm.get_edges_from_nodes();
bm.Input.space = opt.space;
if numel(bm.Input.space) > 1
msg = sprintf('Models can only accept one space.\nGot: %s', ...
bids.internal.create_unordered_list(bm.Input.space));
id = 'tooManySpaces';
logger('ERROR', msg, 'id', id, 'filename', mfilename());
end
bm.validateConstrasts();
bm = bm.update();
filename = fullfile(opt.dir.derivatives, 'models', ...
['model-', ...
bids.internal.camel_case(['default ' strjoin(opt.taskName)]), ...
'_smdl.json']);
bm.write(filename);
msg = sprintf('\nDefault model was created:\n\t%s', bids.internal.format_path(filename));
logger('INFO', msg, 'options', opt, 'filename', mfilename());
opt.model.file = filename;
end