From e83ea8f4b2896b28c544b0c756ae7a778ea5e804 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 12 Nov 2019 23:00:36 +0100 Subject: [PATCH 1/6] fix problematic demo model json - create basic test to validate json model files - add demo output to gitignore --- .gitignore | 4 ++++ demo/model-MoAE_smdl.json | 4 ++++ test/test_modelFiles.m | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 test/test_modelFiles.m diff --git a/.gitignore b/.gitignore index 6fae1c26..b1e660d9 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,7 @@ *.nii opt.mat + +# files in the demo folder related to running the demo analysis +demo/*.zip +demo/output/* diff --git a/demo/model-MoAE_smdl.json b/demo/model-MoAE_smdl.json index 75b890f5..a20d12ae 100644 --- a/demo/model-MoAE_smdl.json +++ b/demo/model-MoAE_smdl.json @@ -5,6 +5,10 @@ "task": "auditory" }, "Steps": [ + { + "Level": "dataset", + "AutoContrasts": [] + }, { "Level": "subject", "AutoContrasts": ["trial_type.listening"], diff --git a/test/test_modelFiles.m b/test/test_modelFiles.m new file mode 100644 index 00000000..78790ccd --- /dev/null +++ b/test/test_modelFiles.m @@ -0,0 +1,37 @@ +function test_modelFiles() +% vague attempt at validating our model files + + +%% +file = fullfile(fileparts(mfilename), '..', 'demo', 'model-MoAE_smdl.json'); + +model = spm_jsonread(file); + +model.Steps{1} + + +%% +file = fullfile(fileparts(mfilename), '..', 'model-visMotionLoc_smdl.json'); + +model = spm_jsonread(file); + +model.Steps{1} + + +%% +file = fullfile(fileparts(mfilename), '..', 'model-motionDecodingUnivariate_smdl.json'); + +model = spm_jsonread(file); + +model.Steps{1} + + +%% +file = fullfile(fileparts(mfilename), '..', 'model-motionDecodingMultivariate_smdl.json'); + +model = spm_jsonread(file); + +model.Steps{1} + + +end \ No newline at end of file From 11b0ac85bf41cdcfaad829804644b535caf4f97e Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Wed, 13 Nov 2019 00:05:49 +0100 Subject: [PATCH 2/6] [TYPO] in BIDS_ffx --- subfun/BIDS_FFX.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subfun/BIDS_FFX.m b/subfun/BIDS_FFX.m index 86357ef2..580cebb7 100644 --- a/subfun/BIDS_FFX.m +++ b/subfun/BIDS_FFX.m @@ -202,7 +202,7 @@ function BIDS_FFX(action, degreeOfSmoothing, opt, isMVPA) JOBS_dir = fullfile(opt.JOBS_dir, subNumber); [~, ~, ~] = mkdir(JOBS_dir); - save(fullfile(JOBS_dir, ['jobs_matlabbatch_SPM12_ffx_', mvpaSuffix,... + save(fullfile(JOBS_dir, ['jobs_matlabbatch_SPM12_FFX_', mvpaSuffix,... num2str(degreeOfSmoothing),'_',opt.taskName,'.mat']), ... 'matlabbatch') From b825d666363bbe804c7d5186bf7722c60c1f9705 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Wed, 13 Nov 2019 00:06:35 +0100 Subject: [PATCH 3/6] Add first version of BIDS_results --- demo/batch_download_run.m | 24 ++++++++ subfun/BIDS_Results.m | 126 ++++++++++++++++++++++++++++++++++++++ subfun/getData.m | 3 + 3 files changed, 153 insertions(+) create mode 100644 subfun/BIDS_Results.m diff --git a/demo/batch_download_run.m b/demo/batch_download_run.m index a9eaec21..a31435f2 100644 --- a/demo/batch_download_run.m +++ b/demo/batch_download_run.m @@ -46,6 +46,29 @@ opt.model.univariate.file = fullfile(WD, 'model-MoAE_smdl.json'); +% specify the result to compute +opt.result.Steps(1) = struct(... + 'Level', 'subject', ... + 'Contrasts', struct(... + 'Name', 'listening', ... % has to match + 'Mask', false, ... % this might need improving if a mask is required + 'MC', 'FWE', ... FWE, none, FDR + 'p', 0.05, ... + 'k', 0, ... + 'NIDM', true) ); + +opt.result.Steps(1).Contrasts(2) = struct(... + 'Name', 'listening_inf_baseline', ... + 'Mask', false, ... + 'MC', 'none', ... FWE, none, FDR + 'p', 0.01, ... + 'k', 0, ... + 'NIDM', true); + + + + + %% Get data fprintf('%-40s:', 'Downloading dataset...'); urlwrite(URL, 'MoAEpilot.zip'); @@ -72,5 +95,6 @@ BIDS_Smoothing(FWHM, opt); BIDS_FFX(1, FWHM, opt, 0); BIDS_FFX(2, FWHM, opt, 0); +BIDS_Results(FWHM, opt, 0) diff --git a/subfun/BIDS_Results.m b/subfun/BIDS_Results.m new file mode 100644 index 00000000..42ed30b4 --- /dev/null +++ b/subfun/BIDS_Results.m @@ -0,0 +1,126 @@ +function BIDS_Results(FFXSmoothing, opt, isMVPA) +% This scripts computes the results for a series of contrast that can be +% specified at the run, subject or dataset step level (see contrast specification following the BIDS stats model +% specification) +% +% FFXSmoothing is the number of the mm smoothing used on the normalized functional files. +% for unsmoothied data FFXSmoothing = 0 + +% if input has no opt, load the opt.mat file +if nargin<1 + load('opt.mat') + fprintf('opt.mat file loaded \n\n') +end + +% JOBS Directory +JOBS_dir = fullfile(opt.JOBS_dir); + +% load the subjects/Groups information and the task name +[group, opt] = getData(opt); + +matlabbatch = []; + +% loop trough the steps and more results to compute for each contrast +% mentioned for each step +for iStep = 1:length(opt.result.Steps) + + for iCon = 1:length(opt.result.Steps(iStep).Contrasts) + + % Depending on the level step we migh have to define a matlabbatch + % for each subject or just on for the whole group + switch opt.result.Steps(iStep).Level + + case 'run' + error('run level not implemented yet'); + + case 'subject' + + for iGroup= 1:length(group) + + % For each subject + for iSub = 1:group(iGroup).numSub + + % Get the Subject ID + subNumber = group(iGroup).subNumber{iSub} ; + + % FFX Directory + ffxDir = getFFXdir(subNumber, FFXSmoothing, opt, isMVPA); + + load(fullfile(ffxDir, 'SPM.mat')) + + % identify which contrast number actually has the name the user asked for + conNb = find ( strcmp({SPM.xCon.name}', opt.result.Steps(iStep).Contrasts(iCon).Name) ); + + if isempty(conNb) + sprintf('List of contrast in this SPM file') + disp({SPM.xCon.name}') + error('This SPM file %s does not contain a contrast named %s', ... + fullfile(Dir, 'SPM.mat'), ... + opt.result.Steps(1).Contrasts(iCon).Name) + end + + matlabbatch = result_matlabbatch(matlabbatch, opt, iStep, iCon, ffxDir, conNb, subNumber, 1); + + end + end + + case 'dataset' + error('dataset level not implemented yet'); + end + end + + +end + +% save the matlabbatch +save(fullfile(JOBS_dir, ... + 'jobs_matlabbatch_SPM12_Results.mat'), ... + 'matlabbatch') + +spm_jobman('run',matlabbatch) + +% move ps file +% TODO + +% rename NIDM file +% TODO + +end + +function matlabbatch = result_matlabbatch(matlabbatch, opt, iStep, iCon, Dir, conNb, label, nsubj) +% outputs the typical matlabbatch to compute the results for a given +% contrast + +matlabbatch{end+1}.spm.stats.results.spmmat = {fullfile(Dir, 'SPM.mat')}; + +matlabbatch{end}.spm.stats.results.conspec.titlestr = opt.result.Steps(iStep).Contrasts(iCon).Name; + +matlabbatch{end}.spm.stats.results.conspec.contrasts = conNb; + +matlabbatch{end}.spm.stats.results.conspec.threshdesc = opt.result.Steps(iStep).Contrasts(iCon).MC; + +matlabbatch{end}.spm.stats.results.conspec.thresh = opt.result.Steps(iStep).Contrasts(iCon).p; + +matlabbatch{end}.spm.stats.results.conspec.extent = opt.result.Steps(iStep).Contrasts(iCon).k; + +matlabbatch{end}.spm.stats.results.conspec.conjunction = 1; + +matlabbatch{end}.spm.stats.results.conspec.mask.none = ~opt.result.Steps(iStep).Contrasts(iCon).Mask; + +matlabbatch{end}.spm.stats.results.units = 1; + +matlabbatch{end}.spm.stats.results.export{1}.ps = true; + +if opt.result.Steps(1).Contrasts(iCon).NIDM + + matlabbatch{end}.spm.stats.results.export{2}.nidm.modality = 'FMRI'; + + matlabbatch{end}.spm.stats.results.export{2}.nidm.refspace = 'ixi'; + + matlabbatch{end}.spm.stats.results.export{2}.nidm.group.nsubj = nsubj; + + matlabbatch{end}.spm.stats.results.export{2}.nidm.group.label = label; + +end + +end \ No newline at end of file diff --git a/subfun/getData.m b/subfun/getData.m index 37f0290a..0aa193c0 100644 --- a/subfun/getData.m +++ b/subfun/getData.m @@ -188,4 +188,7 @@ % specify the model file that contains the contrasts to compute options.contrastList = {}; options.model.file = ''; + +% specify the results to compute +options.result = []; end From 6442fee86bd7bc42afea3d11c074b5d115cafc39 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Wed, 13 Nov 2019 00:30:51 +0100 Subject: [PATCH 4/6] Extend BIDS_results to group level --- batch.m | 40 ++++++++++--------- getOption.m | 32 ++++++++++----- model-balloonanalogriskMultivariate_smdl.json | 13 ++++++ model-balloonanalogriskUnivariate_smdl.json | 17 ++++++++ subfun/BIDS_Results.m | 20 +++++++++- subfun/getData.m | 2 +- 6 files changed, 92 insertions(+), 32 deletions(-) create mode 100644 model-balloonanalogriskMultivariate_smdl.json create mode 100644 model-balloonanalogriskUnivariate_smdl.json diff --git a/batch.m b/batch.m index 77cd7be2..3754485d 100644 --- a/batch.m +++ b/batch.m @@ -17,26 +17,28 @@ checkDependencies(); -% copy raw folder into derivatives folder -BIDS_copyRawFolder(opt, 1) - -% preprocessing -BIDS_STC(opt); -BIDS_SpatialPrepro(opt); -BIDS_Smoothing(6, opt); - -% subject level Univariate -BIDS_FFX(1, 6, opt); -BIDS_FFX(2, 6, opt); - -% group level univariate -BIDS_RFX(1, 6, 6) -BIDS_RFX(2, 6, 6) +% % copy raw folder into derivatives folder +% BIDS_copyRawFolder(opt, 1) +% +% % preprocessing +% BIDS_STC(opt); +% BIDS_SpatialPrepro(opt); +% BIDS_Smoothing(6, opt); + +% % subject level Univariate +% BIDS_FFX(1, 6, opt); +% BIDS_FFX(2, 6, opt); +% +% % group level univariate +% BIDS_RFX(1, 6, 6) +% BIDS_RFX(2, 6, 6) + +BIDS_Results(6, 6, opt, 0) % subject level multivariate -isMVPA=1; -BIDS_FFX(1, 6, opt, isMVPA); -BIDS_FFX(2, 6, opt, isMVPA); -make4Dmaps(6,opt) +% isMVPA=1; +% BIDS_FFX(1, 6, opt, isMVPA); +% BIDS_FFX(2, 6, opt, isMVPA); +% make4Dmaps(6,opt) diff --git a/getOption.m b/getOption.m index 5c137c06..e3c0420e 100644 --- a/getOption.m +++ b/getOption.m @@ -9,16 +9,16 @@ % group of subjects to analyze opt.groups = {''}; % {'blnd', 'ctrl'}; % suject to run in each group -% opt.subjects = {[4:6]}; % {[1:2], [1:2]}; -opt.subjects = {[]}; % {[1:2], [1:2]}; +opt.subjects = {[4:6]}; % {[1:2], [1:2]}; +% opt.subjects = {[]}; % {[1:2], [1:2]}; % task to analyze -opt.taskName = 'MotionDecoding'; +% opt.taskName = 'MotionDecoding'; % opt.taskName = 'visMotion'; -% opt.taskName = 'balloonanalogrisktask'; +opt.taskName = 'balloonanalogrisktask'; @@ -28,9 +28,9 @@ % opt.dataDir = '/Users/mohamed/Desktop/Data/raw'; % opt.dataDir = '/home/remi/BIDS/visMotion/raw'; -opt.dataDir = '/home/remi/BIDS/MotionDecoding/raw'; +% opt.dataDir = '/home/remi/BIDS/MotionDecoding/raw'; -% opt.dataDir = '/home/remi/BIDS/ds001/rawdata'; +opt.dataDir = '/home/remi/BIDS/ds001/rawdata'; % Options for slice time correction @@ -58,11 +58,23 @@ % opt.model.univariate.file = '/home/remi/github/CPP_BIDS_SPM_pipeline/model-visMotionLoc_smdl.json'; -opt.model.univariate.file = '/home/remi/github/CPP_BIDS_SPM_pipeline/model-motionDecodingUnivariate_smdl.json'; -opt.model.multivariate.file = '/home/remi/github/CPP_BIDS_SPM_pipeline/model-motionDecodingMultivariate_smdl.json'; +% opt.model.univariate.file = '/home/remi/github/CPP_BIDS_SPM_pipeline/model-motionDecodingUnivariate_smdl.json'; +% opt.model.multivariate.file = '/home/remi/github/CPP_BIDS_SPM_pipeline/model-motionDecodingMultivariate_smdl.json'; -% opt.model.univariate.file = '/home/remi/github/CPP_BIDS_SPM_pipeline/model-balloonanalogriskUnivariate_smdl.json'; -% opt.model.multivariate.file = '/home/remi/github/CPP_BIDS_SPM_pipeline/model-balloonanalogriskMultivariate_smdl.json'; +opt.model.univariate.file = '/home/remi/github/CPP_BIDS_SPM_pipeline/model-balloonanalogriskUnivariate_smdl.json'; +opt.model.multivariate.file = '/home/remi/github/CPP_BIDS_SPM_pipeline/model-balloonanalogriskMultivariate_smdl.json'; + + +% specify the result to compute +opt.result.Steps(1) = struct(... + 'Level', 'dataset', ... + 'Contrasts', struct(... + 'Name', 'pumps_demean', ... % has to match + 'Mask', false, ... % this might need improving if a mask is required + 'MC', 'none', ... FWE, none, FDR + 'p', 0.05, ... + 'k', 0, ... + 'NIDM', true) ); % Save the opt variable as a mat file to load directly in the preprocessing diff --git a/model-balloonanalogriskMultivariate_smdl.json b/model-balloonanalogriskMultivariate_smdl.json new file mode 100644 index 00000000..a44ec3bc --- /dev/null +++ b/model-balloonanalogriskMultivariate_smdl.json @@ -0,0 +1,13 @@ +{ + "Name": "balloonanalogrisk", + "Description": "contrasts for the -balloonanalogrisk dataset", + "Input": { + "task": "balloonanalogrisktask" + }, + "Steps": [ + { + "Level": "run", + "AutoContrasts": ["trial_type.pumps_demean"] + } + ] +} diff --git a/model-balloonanalogriskUnivariate_smdl.json b/model-balloonanalogriskUnivariate_smdl.json new file mode 100644 index 00000000..de0ab4fa --- /dev/null +++ b/model-balloonanalogriskUnivariate_smdl.json @@ -0,0 +1,17 @@ +{ + "Name": "balloonanalogrisk", + "Description": "contrasts for the -balloonanalogrisk dataset", + "Input": { + "task": "balloonanalogrisktask" + }, + "Steps": [ + { + "Level": "subject", + "AutoContrasts": ["trial_type.pumps_demean", "trial_type.cash_demean"] + }, + { + "Level": "dataset", + "AutoContrasts": ["pumps_demean"] + } + ] +} diff --git a/subfun/BIDS_Results.m b/subfun/BIDS_Results.m index 42ed30b4..cd97e075 100644 --- a/subfun/BIDS_Results.m +++ b/subfun/BIDS_Results.m @@ -1,4 +1,4 @@ -function BIDS_Results(FFXSmoothing, opt, isMVPA) +function BIDS_Results(FFXSmoothing, ConSmoothing, opt, isMVPA) % This scripts computes the results for a series of contrast that can be % specified at the run, subject or dataset step level (see contrast specification following the BIDS stats model % specification) @@ -36,6 +36,8 @@ function BIDS_Results(FFXSmoothing, opt, isMVPA) case 'subject' for iGroup= 1:length(group) + + groupName = group(iGroup).name ; % For each subject for iSub = 1:group(iGroup).numSub @@ -65,13 +67,26 @@ function BIDS_Results(FFXSmoothing, opt, isMVPA) end case 'dataset' - error('dataset level not implemented yet'); + + % Define the RFX folder name and create it in the derivatives + % directory + rfxDir = fullfile(opt.dataDir, '..', 'derivatives', 'SPM12_CPPL', ... + ['RFX_', opt.taskName],... + ['RFX_FunctSmooth', num2str(FFXSmoothing),... + '_ConSmooth_', num2str(ConSmoothing)], ... + opt.result.Steps(iStep).Contrasts(iCon).Name) ; + + load(fullfile(rfxDir, 'SPM.mat')) + + matlabbatch = result_matlabbatch(matlabbatch, opt, iStep, iCon, rfxDir, 1, 'group level', SPM.nscan); + end end end +if ~isempty(matlabbatch) % save the matlabbatch save(fullfile(JOBS_dir, ... 'jobs_matlabbatch_SPM12_Results.mat'), ... @@ -84,6 +99,7 @@ function BIDS_Results(FFXSmoothing, opt, isMVPA) % rename NIDM file % TODO +end end diff --git a/subfun/getData.m b/subfun/getData.m index 0aa193c0..bee94d7f 100644 --- a/subfun/getData.m +++ b/subfun/getData.m @@ -190,5 +190,5 @@ options.model.file = ''; % specify the results to compute -options.result = []; +options.result.Steps = []; end From 306aefa76ede027fae6fb1b87a98708510497de8 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Wed, 13 Nov 2019 19:39:59 +0100 Subject: [PATCH 5/6] Clean up --- README.md | 52 +++++++++++++------ batch.m | 38 +++++++------- getOption.m | 39 ++++---------- getOption_template | 26 +++++++--- ...el-balloonanalogriskMultivariate_smdl.json | 0 ...odel-balloonanalogriskUnivariate_smdl.json | 0 6 files changed, 85 insertions(+), 70 deletions(-) rename model-balloonanalogriskMultivariate_smdl.json => model/model-balloonanalogriskMultivariate_smdl.json (100%) rename model-balloonanalogriskUnivariate_smdl.json => model/model-balloonanalogriskUnivariate_smdl.json (100%) diff --git a/README.md b/README.md index a23dbc33..7042cdb5 100644 --- a/README.md +++ b/README.md @@ -5,25 +5,30 @@ -- [Instructions for SPM12 Preprocessing Pipeline](#instructions-for-spm12-preprocessing-pipeline) +- [Instructions for SPM12 Preprocessing Pipeline](#instructions-for-spm12-preprocessing-pipeline) - [Dependencies](#dependencies) - [General description](#general-description) - [Assumption](#assumption) - [Setting up](#setting-up) + - [getOptions](#getoptions) + - [model JSON files](#model-json-files) - [Order of the analysis](#order-of-the-analysis) - [Docker](#docker) - [build docker image](#build-docker-image) - [run docker image](#run-docker-image) + - [MRIQC](#mriqc) - [Details about some steps](#details-about-some-steps) - [Slice timing correction](#slice-timing-correction) - [Boiler plate methods section](#boiler-plate-methods-section) - [Preprocessing](#preprocessing) - [fMRI data analysis](#fmri-data-analysis) - [References](#references) - - [Testing](#testing) + - [Unit testing](#unit-testing) + - [Contributors ✨](#contributors-) + ## Dependencies Make sure that the following toolboxes are installed and added to the matlab path. @@ -38,6 +43,7 @@ For instructions see the following links: For simplicity the NIfTI tools toolbox has been added to this repo in the `subfun` folder. + ## General description This set of function will read and unzip the data from a [BIDS data set](https://bids.neuroimaging.io/). It will then perform: @@ -53,6 +59,7 @@ It can also prepare the data to run an MVPA analysis by running a GLM for each s The core functions are in the sub-function folder `subfun` + ## Assumption At the moment this pipeline makes some assumptions: @@ -60,12 +67,13 @@ At the moment this pipeline makes some assumptions: - it assumes the metadata for a given task are the same as those the first run of the first subject this pipeline is being run on, - it assumes that group are defined in the subject field (eg `sub-ctrl01`, `sub-blind01`, ...) and not in the `participants.tsv` file. + ## Setting up ### getOptions -All the details specific to your analysis should be set in the `getOptions.m`. +All the details specific to your analysis should be set in the `getOptions.m`. There is a getOption_template file that shows you would set up the getOption file if one wanted to analyse the [ds001 data set from OpenNeuro](https://openneuro.org/datasets/ds000001/versions/57fecb0ccce88d000ac17538). Set the group of subjects to analyze. ``` @@ -102,6 +110,7 @@ The directory where your files are located on your computer: make sure you have Some more SPM options can be set in the `spm_my_defaults.m`. + ### model JSON files This files allow you to specify which contrasts to run and follow the BIDS statistical model extension and as implement by [fitlins](https://fitlins.readthedocs.io/en/latest/model.html) @@ -153,47 +162,51 @@ In brief this means: - at the subject level automatically compute the t contrast against baseline for the condition `motion`and `static` and compute the t-contrats for motion VS static with these given weights. - at the level of the data set (so RFX) do the t contrast of the `motion`, `static`, `motion VS static`. +We are currently using this to run different subject level GLM models for our univariate and multivariate analysis where in the first one we compute a con image that averages the beta image of all the runs where as in the latter case we get one con image for each run. + ## Order of the analysis 1. __Remove Dummy Scans__: -Unzip bold files and removes dummy scans by running the script (to be run even if `opt.numDummies` set to `0`): -`BIDS_rmDummies.m` +Unzip bold files and removes dummy scans by running the script (to be run even if `opt.numDummies` set to `0`): `BIDS_rmDummies.m` + +2. __Slice Time Correction__: Performs Slice Time Correction (STC) of the functional volumes by running the script: `BIDS_STC.m` -2. __Slice Time Correction__: Performs Slice Time Correction (STC) of the functional volumes by running the script: -`BIDS_STC.m` STC will be performed using the information provided in the BIDS data set. It will use the mid-volume acquisition time point as as reference. + The `getOption.m` fields related to STC can still be used to do some slice timing correction even no information is can be found in the BIDS data set. + In general slice order and reference slice is entered in time unit (ms) (this is the BIDS way of doing things) instead of the slice index of the reference slice (the "SPM" way of doing things). + More info available on this page of the [SPM wikibook](https://en.wikibooks.org/wiki/SPM/Slice_Timing). 3. __Spatial Preprocessing__: -Performs spatial preprocessing by running the script: -`BIDS_SpatialPrepro.m` +Performs spatial preprocessing by running the script: `BIDS_SpatialPrepro.m` 4. __SMOOTHING__: -Performs smoothing of the functional data by running the script: -`BIDS_Smoothing.m` +Performs smoothing of the functional data by running the script: `BIDS_Smoothing.m` 5. __FIXED EFFECTS ANALYSIS (FIRST-LEVEL ANALYSIS)__: -Performs the fixed effects analysis by running the ffx script: -`BIDS_FFX.m` +Performs the fixed effects analysis by running the ffx script: `BIDS_FFX.m` This will run twice, once for model specification and another time for model estimation. See the function for more details. This will take each condition present in the `events.tsv` file of each run and convolve it with a canonical HRF. It will also add the 6 realignment parameters of every run as confound regressors. 6. __RANDOM EFFECTS ANALYSIS (SECOND-LEVEL ANALYSIS)__: -Performs the random effects analysis by running the RFX script: -`BIDS_RFX.m` +Performs the random effects analysis by running the RFX script: `BIDS_RFX.m` + +7. __GET THE RESULTS FROM A SPECIFIC CONTRAST__: `BIDS_Results.m` - See __"batch.m"__ for examples and for the order of the scripts. - See __"batch_dowload_run.m"__ for an example of how to download a data set and analyze it all in one go. + ## Docker The recipe to build the docker image is in the `Dockerfile` + ### build docker image To build the image with with octave and SPM the `Dockerfile` just type : @@ -202,6 +215,7 @@ To build the image with with octave and SPM the `Dockerfile` just type : This will create an image with the tag name `cpp_spm_octave:0.0.1` + ### run docker image The following code would start the docker image and would map 2 folders one for `output` and one for `code` you want to run. @@ -231,6 +245,7 @@ docker run -it --rm -v $data_dir/raw:/data:ro -v $data_dir:/out poldracklab/mriq ## Details about some steps + ### Slice timing correction BELOW: some comments from [here](http://mindhive.mit.edu/node/109) on STC, when it should be applied @@ -243,8 +258,10 @@ _If you do slice timing correction before realignment, you might look down your _There's no way to avoid all the error (short of doing a four-dimensional realignment process combining spatial and temporal correction - Remi's note: fMRIprep does it), but I believe the current thinking is that doing slice timing first minimizes your possible error. The set of voxels subject to such an interpolation error is small, and the interpolation into another TR will also be small and will only affect a few TRs in the time course. By contrast, if one realigns first, many voxels in a slice could be affected at once, and their whole time courses will be affected. I think that's why it makes sense to do slice timing first. That said, here's some articles from the SPM e-mail list that comment helpfully on this subject both ways, and there are even more if you do a search for "slice timing AND before" in the archives of the list._ + ## Boiler plate methods section + ### Preprocessing The fMRI data were pre-processed and analyzed using statistical parametric mapping (SPM12 – v7487; Wellcome Center for Neuroimaging, London, UK; www.fil.ion.ucl.ac.uk/spm) running on {octave 4.{??} / matlab 20{XX} (Mathworks)}. @@ -263,6 +280,7 @@ The anatomical T1 image was bias field corrected, segmented and normalized to MN Functional MNI normalized images were then spatially smoothed using a 3D gaussian kernel (FWHM = {XX} mm). + ### fMRI data analysis At the subject level, we performed a mass univariate analysis with a linear regression at each voxel of the brain, using generalized least squares with a global FAST model to account for temporal auto-correlation (Corbin et al, 2018) and a drift fit with discrete cosine transform basis (128 seconds cut-off). Image intensity scaling was done run-wide before statistical modeling such that the mean image will have mean intracerebral intensity of 100. @@ -279,6 +297,7 @@ Table of constrast with weight: WIP Group level: WIP + ### References Friston KJ, Ashburner J, Frith CD, Poline J-B, Heather JD & Frackowiak RSJ (1995) Spatial registration and normalization of images Hum. Brain Map. 2:165-189 @@ -286,10 +305,11 @@ Friston KJ, Ashburner J, Frith CD, Poline J-B, Heather JD & Frackowiak RSJ (1995 Corbin, N., Todd, N., Friston, K. J. & Callaghan, M. F. Accurate modeling of temporal correlations in rapidly sampled fMRI time series. Hum. Brain Mapp. 39, 3884–3897 (2018). -## Testing +## Unit testing All tests are in the test folder. There is also an empty dummy BIDS dataset that is partly created using the bash script `createDummyDataSet.sh`. + ## Contributors ✨ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): diff --git a/batch.m b/batch.m index 3754485d..250e7e79 100644 --- a/batch.m +++ b/batch.m @@ -17,28 +17,28 @@ checkDependencies(); -% % copy raw folder into derivatives folder -% BIDS_copyRawFolder(opt, 1) -% -% % preprocessing -% BIDS_STC(opt); -% BIDS_SpatialPrepro(opt); -% BIDS_Smoothing(6, opt); - -% % subject level Univariate -% BIDS_FFX(1, 6, opt); -% BIDS_FFX(2, 6, opt); -% -% % group level univariate -% BIDS_RFX(1, 6, 6) -% BIDS_RFX(2, 6, 6) +% copy raw folder into derivatives folder +BIDS_copyRawFolder(opt, 1) + +% preprocessing +BIDS_STC(opt); +BIDS_SpatialPrepro(opt); +BIDS_Smoothing(6, opt); + +% subject level Univariate +BIDS_FFX(1, 6, opt); +BIDS_FFX(2, 6, opt); + +% group level univariate +BIDS_RFX(1, 6, 6) +BIDS_RFX(2, 6, 6) BIDS_Results(6, 6, opt, 0) % subject level multivariate -% isMVPA=1; -% BIDS_FFX(1, 6, opt, isMVPA); -% BIDS_FFX(2, 6, opt, isMVPA); -% make4Dmaps(6,opt) +isMVPA=1; +BIDS_FFX(1, 6, opt, isMVPA); +BIDS_FFX(2, 6, opt, isMVPA); +make4Dmaps(6,opt) diff --git a/getOption.m b/getOption.m index e3c0420e..4e988f8d 100644 --- a/getOption.m +++ b/getOption.m @@ -7,30 +7,18 @@ end % group of subjects to analyze -opt.groups = {''}; % {'blnd', 'ctrl'}; +opt.groups = {''}; % suject to run in each group -opt.subjects = {[4:6]}; % {[1:2], [1:2]}; -% opt.subjects = {[]}; % {[1:2], [1:2]}; +opt.subjects = {[1:2]}; % task to analyze -% opt.taskName = 'MotionDecoding'; - -% opt.taskName = 'visMotion'; - -opt.taskName = 'balloonanalogrisktask'; - +opt.taskName = 'MotionDecoding'; % The directory where the data are located - -% opt.dataDir = '/Users/mohamed/Desktop/MotionWorkshop/raw'; -% opt.dataDir = '/Users/mohamed/Desktop/Data/raw'; - -% opt.dataDir = '/home/remi/BIDS/visMotion/raw'; -% opt.dataDir = '/home/remi/BIDS/MotionDecoding/raw'; - -opt.dataDir = '/home/remi/BIDS/ds001/rawdata'; +opt.dataDir = '/Users/mohamed/Desktop/MotionWorkshop/raw'; +opt.dataDir = '/Users/mohamed/Desktop/Data/raw'; % Options for slice time correction @@ -51,25 +39,17 @@ % Suffix output directory for the saved jobs opt.JOBS_dir = fullfile(opt.dataDir, '..', 'derivatives', 'SPM12_CPPL', 'JOBS', opt.taskName); -% specify the model file that contains the contrasts to compute - -% opt.model.univariate.file = '/Users/mohamed/Documents/GitHub/BIDS_fMRI_scripts/model-motionDecodingUnivariate_smdl.json'; -% opt.model.multivariate.file = '/Users/mohamed/Documents/GitHub/BIDS_fMRI_scripts/model-motionDecodingMultivariate_smdl.json'; - -% opt.model.univariate.file = '/home/remi/github/CPP_BIDS_SPM_pipeline/model-visMotionLoc_smdl.json'; -% opt.model.univariate.file = '/home/remi/github/CPP_BIDS_SPM_pipeline/model-motionDecodingUnivariate_smdl.json'; -% opt.model.multivariate.file = '/home/remi/github/CPP_BIDS_SPM_pipeline/model-motionDecodingMultivariate_smdl.json'; - -opt.model.univariate.file = '/home/remi/github/CPP_BIDS_SPM_pipeline/model-balloonanalogriskUnivariate_smdl.json'; -opt.model.multivariate.file = '/home/remi/github/CPP_BIDS_SPM_pipeline/model-balloonanalogriskMultivariate_smdl.json'; +% specify the model file that contains the contrasts to compute +opt.model.univariate.file = '/Users/mohamed/Documents/GitHub/BIDS_fMRI_scripts/model-motionDecodingUnivariate_smdl.json'; +opt.model.multivariate.file = '/Users/mohamed/Documents/GitHub/BIDS_fMRI_scripts/model-motionDecodingMultivariate_smdl.json'; % specify the result to compute opt.result.Steps(1) = struct(... 'Level', 'dataset', ... 'Contrasts', struct(... - 'Name', 'pumps_demean', ... % has to match + 'Name', 'Vis_U', ... % has to match one of the contrast defined in the model json file 'Mask', false, ... % this might need improving if a mask is required 'MC', 'none', ... FWE, none, FDR 'p', 0.05, ... @@ -81,4 +61,5 @@ % scripts save('opt.mat','opt') + end diff --git a/getOption_template b/getOption_template index ae5cac84..25356e00 100644 --- a/getOption_template +++ b/getOption_template @@ -7,17 +7,18 @@ if nargin<1 end % group of subjects to analyze -opt.groups = {''}; % {'blnd', 'ctrl'}; +opt.groups = {''}; % suject to run in each group -opt.subjects = {[]}; % {[1:2], [1:2]}; +opt.subjects = {[]}; % task to analyze -opt.taskName = 'visMotion'; +opt.taskName = 'balloonanalogrisktask'; -% The directory where the derivatives are located -opt.dataDir = '/home/remi/BIDS/visMotion/raw'; + +% The directory where the data are located +opt.dataDir = '/home/remi/BIDS/ds001/rawdata'; % Options for slice time correction @@ -39,7 +40,20 @@ opt.funcVoxelDims = []; opt.JOBS_dir = fullfile(opt.dataDir, '..', 'derivatives', 'SPM12_CPPL', 'JOBS', opt.taskName); % specify the model file that contains the contrasts to compute -opt.model.univariate.file = '/home/remi/github/CPP_BIDS_SPM_pipeline/model-visMotionLoc_smdl.json'; +opt.model.univariate.file = fullfile(fileparts(mfilename('fullpath')), 'model', model-balloonanalogriskUnivariate_smdl.json'); +opt.model.multivariate.file = fullfile(fileparts(mfilename('fullpath')), 'model', model-balloonanalogriskMultivariate_smdl.json'); + + +% specify the result to compute +opt.result.Steps(1) = struct(... + 'Level', 'dataset', ... + 'Contrasts', struct(... + 'Name', 'pumps_demean', ... % has to match + 'Mask', false, ... % this might need improving if a mask is required + 'MC', 'none', ... FWE, none, FDR + 'p', 0.05, ... + 'k', 0, ... + 'NIDM', true) ); % Save the opt variable as a mat file to load directly in the preprocessing diff --git a/model-balloonanalogriskMultivariate_smdl.json b/model/model-balloonanalogriskMultivariate_smdl.json similarity index 100% rename from model-balloonanalogriskMultivariate_smdl.json rename to model/model-balloonanalogriskMultivariate_smdl.json diff --git a/model-balloonanalogriskUnivariate_smdl.json b/model/model-balloonanalogriskUnivariate_smdl.json similarity index 100% rename from model-balloonanalogriskUnivariate_smdl.json rename to model/model-balloonanalogriskUnivariate_smdl.json From 85a1644ea68799eb386ab30efd4706a9eb0eee3c Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Wed, 13 Nov 2019 19:51:37 +0100 Subject: [PATCH 6/6] add model files to test and fix json files --- .../model-balloonanalogriskMultivariate_smdl.json | 11 ++++++++++- model/model-balloonanalogriskUnivariate_smdl.json | 7 ++++++- test/test_modelFiles.m | 14 ++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/model/model-balloonanalogriskMultivariate_smdl.json b/model/model-balloonanalogriskMultivariate_smdl.json index a44ec3bc..2827c98b 100644 --- a/model/model-balloonanalogriskMultivariate_smdl.json +++ b/model/model-balloonanalogriskMultivariate_smdl.json @@ -1,13 +1,22 @@ { "Name": "balloonanalogrisk", - "Description": "contrasts for the -balloonanalogrisk dataset", + "Description": "contrasts for the balloonanalogrisk dataset", "Input": { "task": "balloonanalogrisktask" }, "Steps": [ + { + "Level": "subject", + "AutoContrasts": [], + "Contrasts": [] + }, { "Level": "run", "AutoContrasts": ["trial_type.pumps_demean"] + }, + { + "Level": "dataset", + "AutoContrasts": [] } ] } diff --git a/model/model-balloonanalogriskUnivariate_smdl.json b/model/model-balloonanalogriskUnivariate_smdl.json index de0ab4fa..e4205f6a 100644 --- a/model/model-balloonanalogriskUnivariate_smdl.json +++ b/model/model-balloonanalogriskUnivariate_smdl.json @@ -1,10 +1,15 @@ { "Name": "balloonanalogrisk", - "Description": "contrasts for the -balloonanalogrisk dataset", + "Description": "contrasts for the balloonanalogrisk dataset", "Input": { "task": "balloonanalogrisktask" }, "Steps": [ + { + "Level": "run", + "AutoContrasts": [], + "Contrasts": [] + }, { "Level": "subject", "AutoContrasts": ["trial_type.pumps_demean", "trial_type.cash_demean"] diff --git a/test/test_modelFiles.m b/test/test_modelFiles.m index 78790ccd..ce3c8ae0 100644 --- a/test/test_modelFiles.m +++ b/test/test_modelFiles.m @@ -33,5 +33,19 @@ function test_modelFiles() model.Steps{1} +%% +file = fullfile(fileparts(mfilename), '..', 'model', 'model-balloonanalogriskUnivariate_smdl.json'); + +model = spm_jsonread(file); + +model.Steps{1} + +%% +file = fullfile(fileparts(mfilename), '..', 'model', 'model-balloonanalogriskMultivariate_smdl.json'); + +model = spm_jsonread(file); + +model.Steps{1} + end \ No newline at end of file