diff --git a/demos/openneuro/ds000114_getOption.m b/demos/openneuro/ds000114_getOption.m index 5797314e..87e28c5d 100644 --- a/demos/openneuro/ds000114_getOption.m +++ b/demos/openneuro/ds000114_getOption.m @@ -4,10 +4,6 @@ % returns a structure that contains the options chosen by the user to run % slice timing correction, pre-processing, FFX, RFX. - if nargin < 1 - opt = []; - end - % The directory where the data are located opt.dataDir = '/home/remi/openneuro/ds000114/raw'; @@ -18,7 +14,7 @@ opt.taskName = 'linebisection'; opt.anatReference.type = 'T1w'; - opt.anatReference.session = 2; + opt.anatReference.session = 'test'; % Uncomment the lines below to run preprocessing % - don't use realign and unwarp @@ -28,11 +24,11 @@ opt.model.file = fullfile(fileparts(mfilename('fullpath')), ... 'models', ... - 'model-ds000114-linebisection_smdl.json'); + 'model-ds000114-lineBisectionRunLevel_smdl.json'); % specify the result to compute opt.result.Steps(1) = struct( ... - 'Level', 'subject', ... + 'Level', 'run', ... 'Contrasts', struct( ... 'Name', 'Correct_Task', ... % has to match 'Mask', false, ... diff --git a/demos/openneuro/ds000114_run.m b/demos/openneuro/ds000114_run.m index 56f61cfd..be68a201 100644 --- a/demos/openneuro/ds000114_run.m +++ b/demos/openneuro/ds000114_run.m @@ -30,8 +30,31 @@ bidsSmoothing(FWHM, opt); +%% Run level analysis: as for MVPA + bidsFFX('specifyAndEstimate', opt, FWHM); bidsFFX('contrasts', opt, FWHM); + +bidsConcatBetaTmaps(opt, FWHM, false, false); + +%% Subject level analysis: for regular univariate + +opt.model.file = fullfile(fileparts(mfilename('fullpath')), ... + 'models', ... + 'model-ds000114-linebisection_smdl.json'); + +bidsFFX('specifyAndEstimate', opt, FWHM); + +opt.result.Steps(1) = struct( ... + 'Level', 'subject', ... + 'Contrasts', struct( ... + 'Name', 'Correct_Task', ... % has to match + 'Mask', false, ... + 'MC', 'FWE', ... FWE, none, FDR + 'p', 0.05, ... + 'k', 0)); + +bidsFFX('contrasts', opt, FWHM); bidsResults(opt, FWHM); bidsRFX('smoothContrasts', opt, FWHM, conFWHM); diff --git a/demos/openneuro/models/model-ds000114-lineBisectionRunLevel_smdl.json b/demos/openneuro/models/model-ds000114-lineBisectionRunLevel_smdl.json new file mode 100644 index 00000000..c58c3c27 --- /dev/null +++ b/demos/openneuro/models/model-ds000114-lineBisectionRunLevel_smdl.json @@ -0,0 +1,31 @@ +{ + "Name": "run level", + "Description": "contrasts to compute for the line bisection task", + "Input": { + "task": "linebisection" + }, + "Steps": [ + { + "Level": "run", + "Model": { + "X": [ + "trial_type.Correct_Task", + "trial_type.Incorrect_Task", + "trial_type.No_Response_Task", + "trial_type.Response_Control", + "trial_type.No_Response_Control", + "trans_x", + "trans_y", + "trans_z", + "rot_x", + "rot_y", + "rot_z" + ] + }, + "AutoContrasts": [ + "trial_type.Correct_Task", + "trial_type.Incorrect_Task" + ] + } + ] +} \ No newline at end of file diff --git a/demos/openneuro/models/model-ds000114-linebisection_smdl.json b/demos/openneuro/models/model-ds000114-linebisection_smdl.json index 7bd81d2c..dae89ed5 100644 --- a/demos/openneuro/models/model-ds000114-linebisection_smdl.json +++ b/demos/openneuro/models/model-ds000114-linebisection_smdl.json @@ -14,10 +14,18 @@ "trial_type.No_Response_Task", "trial_type.Response_Control", "trial_type.No_Response_Control", - "trans_x", "trans_y", "trans_z", "rot_x", "rot_y", "rot_z" + "trans_x", + "trans_y", + "trans_z", + "rot_x", + "rot_y", + "rot_z" ] }, - "AutoContrasts": ["trial_type.Correct_Task", "trial_type.Incorrect_Task"] + "AutoContrasts": [ + "trial_type.Correct_Task", + "trial_type.Incorrect_Task" + ] }, { "Level": "run", @@ -28,14 +36,25 @@ "trial_type.No_Response_Task", "trial_type.Response_Control", "trial_type.No_Response_Control", - "trans_x", "trans_y", "trans_z", "rot_x", "rot_y", "rot_z" + "trans_x", + "trans_y", + "trans_z", + "rot_x", + "rot_y", + "rot_z" ] }, - "AutoContrasts": ["trial_type.Correct_Task", "trial_type.Incorrect_Task"] + "AutoContrasts": [ + "trial_type.Correct_Task", + "trial_type.Incorrect_Task" + ] }, { "Level": "dataset", - "AutoContrasts": ["trial_type.Correct_Task", "trial_type.Incorrect_Task"] + "AutoContrasts": [ + "trial_type.Correct_Task", + "trial_type.Incorrect_Task" + ] } ] } \ No newline at end of file diff --git a/src/workflows/bidsConcatBetaTmaps.m b/src/workflows/bidsConcatBetaTmaps.m index dc757327..1fcb53dc 100644 --- a/src/workflows/bidsConcatBetaTmaps.m +++ b/src/workflows/bidsConcatBetaTmaps.m @@ -15,8 +15,14 @@ function bidsConcatBetaTmaps(opt, funcFWHM, deleteIndBeta, deleteIndTmaps) % :param deleteIndTmaps: decide to delete t-maps % :type funcFWHM: (boolean) % + % When concatenating betamaps: + % + % Ensures that there is only 1 image per "contrast". + % Creates a tsv that lists the content of the 4D image. + % This TSV is in the subject level GLM folder where the beta map came from. + % This TSV file is named ``sub-subLabel_task-taskName_space-space_labelfold.tsv``. + % - % delete individual Beta and tmaps if nargin < 3 deleteIndBeta = 1; deleteIndTmaps = 1; @@ -34,6 +40,8 @@ function bidsConcatBetaTmaps(opt, funcFWHM, deleteIndBeta, deleteIndTmaps) ffxDir = getFFXdir(subLabel, funcFWHM, opt); + load(fullfile(ffxDir, 'SPM.mat')); + contrasts = specifyContrasts(ffxDir, opt.taskName, opt); beta_maps = cell(length(contrasts), 1); @@ -41,8 +49,25 @@ function bidsConcatBetaTmaps(opt, funcFWHM, deleteIndBeta, deleteIndTmaps) % path to beta and t-map files. for iContrast = 1:length(beta_maps) - % Note that the betas are created from the idx (Beta_idx(iBeta)) - fileName = sprintf('beta_%04d.nii', find(contrasts(iContrast).C)); + + betasIndices = find(contrasts(iContrast).C); + + if numel(betasIndices) > 1 + error('Supposed to concatenate one beta image per contrast.'); + end + + % for this beta iamge we identify + % - which run it came from + % - the exact condition name stored in the SPM.mat + % so they can be saved in a tsv for for "label" and "fold" for MVPA + tmp = cat(1, SPM.Sess(:).col) == betasIndices; + runs(iContrast, 1) = find(any(tmp, 2)); + + tmp = SPM.xX.name{betasIndices}; + parts = strsplit(tmp, ' '); + conditions{iContrast, 1} = strjoin(parts(2:end), ' '); + + fileName = sprintf('beta_%04d.nii', betasIndices); fileName = validationInputFile(ffxDir, fileName); beta_maps{iContrast, 1} = [fileName, ',1']; @@ -50,8 +75,22 @@ function bidsConcatBetaTmaps(opt, funcFWHM, deleteIndBeta, deleteIndTmaps) fileName = sprintf('spmT_%04d.nii', iContrast); fileName = validationInputFile(ffxDir, fileName); t_maps{iContrast, 1} = [fileName, ',1']; + end + % tsv + nameStructure = struct( ... + 'ext', '.tsv', ... + 'type', 'labelfold', ... + 'sub', subLabel, ... + 'task', opt.taskName, ... + 'space', opt.space); + tsvName = createFilename(nameStructure); + + tsvContent = struct('folds', runs, 'labels', {conditions}); + + spm_save(fullfile(ffxDir, tsvName), tsvContent); + % beta maps outputName = ['4D_beta_', num2str(funcFWHM), '.nii'];