diff --git a/.github/workflows/miss_hit.yml b/.github/workflows/miss_hit.yml index d4cb7ae8..4603893a 100644 --- a/.github/workflows/miss_hit.yml +++ b/.github/workflows/miss_hit.yml @@ -28,7 +28,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip setuptools - pip3 install install miss_hit + pip3 install miss_hit - name: Miss_hit code quality run: | diff --git a/.travis.yml b/.travis.yml index faa12678..63e8b15f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,61 +2,74 @@ # This will only work on your repo if you have an account on travis and you # have set it up to run continuous integration on this this repo -# Linux distribution (bionic beaver) dist: bionic -# Language and version -language: python -python: - - "3.6" # current default Python on Travis CI +language: node_js +node_js: + - "10" cache: - apt: true # only works with Pro version + apt: true directories: - - node_modules # NPM packages for the remark markdown linter + - node_modules +# only run the CI for those branches branches: - only: # only run the CI for those branches - - master - - dev + only: + - master + - dev env: global: - OCTFLAGS="--no-gui --no-window-system --silent" -jobs: +# TODO maybe this could be refactored as this is not needed to check the +# the markdown linting +install: + # install octave + - travis_retry sudo apt-get -y -qq update + - travis_retry sudo apt-get -y install octave + - travis_retry sudo apt-get -y install liboctave-dev + + # install SPM and the relevant patches for octave + - git clone https://github.com/spm/spm12.git --depth 1 + - make -C spm12/src PLATFORM=octave distclean + - make -C spm12/src PLATFORM=octave + - make -C spm12/src PLATFORM=octave install + # update octave path + - octave $OCTFLAGS --eval "addpath(genpath(fullfile(pwd, 'lib'))); savepath();" + - octave $OCTFLAGS --eval "addpath(genpath(fullfile(pwd, 'src'))); savepath();" + - octave $OCTFLAGS --eval "addpath(fullfile(pwd, 'spm12')); savepath();" + +jobs: include: - # names the first job + #------------------------------------------------------------------------- + # first job + #------------------------------------------------------------------------- - name: "Unit tests and coverage" - before_install: - # install octave - - travis_retry sudo apt-get -y -qq update - - travis_retry sudo apt-get -y install octave - - travis_retry sudo apt-get -y install liboctave-dev + before_script: + # install MOX unit - git clone https://github.com/MOxUnit/MOxUnit.git --depth 1 - cd MOxUnit - make install - cd .. + # install MOcov - git clone https://github.com/MOcov/MOcov.git --depth 1 - cd MOcov - make install - cd .. - # install SPM and the relevant patches for octave - - git clone https://github.com/spm/spm12.git --depth 1 - - make -C spm12/src PLATFORM=octave distclean - - make -C spm12/src PLATFORM=octave - - make -C spm12/src PLATFORM=octave install + # get data - output_folder='demos/MoAE/output/' - mkdir $output_folder - curl http://www.fil.ion.ucl.ac.uk/spm/download/data/MoAEpilot/MoAEpilot.bids.zip --output $output_folder'MoAEpilot.zip' - unzip $output_folder'MoAEpilot.zip' -d $output_folder - + script: - octave $OCTFLAGS --eval "runTests" - cat test_report.log | grep 0 @@ -65,11 +78,28 @@ jobs: after_success: - bash <(curl -s https://codecov.io/bash) + #------------------------------------------------------------------------- + # second job + #------------------------------------------------------------------------- - name: "Check markdown" - language: node_js - node_js: - - "10" + before_script: + # install node.js dependencies - npm install `cat npm-requirements.txt` + + script: + - remark *.md --frail + - remark ./demos/ --frail + - remark ./docs/ --frail + - remark ./tests/ --frail + + #------------------------------------------------------------------------- + # third job + #------------------------------------------------------------------------- + - name: "Run demo" + + if: branch = master + script: - - remark ./docs/ --frail \ No newline at end of file + - cd demos/MoAE + - octave $OCTFLAGS --eval "MoAEpilot_run" \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index a63e8576..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,178 +0,0 @@ -# Changelog - -## [Unreleased](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/tree/HEAD) - -[Full Changelog](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/compare/v0.0.3...HEAD) - -**Closed issues:** - -- add code coverage - [\#77](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/issues/77) -- getData :Accommidate scripts for structural analysis \(without funtional\). - [\#68](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/issues/68) - -**Merged pull requests:** - -- major refactoring reporting for duty - [\#79](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/79) - ([Remi-Gau](https://github.com/Remi-Gau)) -- fix linter and use Mox unit for testing - [\#76](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/76) - ([Remi-Gau](https://github.com/Remi-Gau)) -- reorganize and set up MH linter - [\#75](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/75) - ([Remi-Gau](https://github.com/Remi-Gau)) -- add octave in dependencies - [\#71](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/71) - ([Remi-Gau](https://github.com/Remi-Gau)) -- allow getData to query only anatomical data - [\#69](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/69) - ([Remi-Gau](https://github.com/Remi-Gau)) -- update print credit - [\#63](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/63) - ([Remi-Gau](https://github.com/Remi-Gau)) -- update DOI - [\#62](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/62) - ([Remi-Gau](https://github.com/Remi-Gau)) -- update DOI badge - [\#61](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/61) - ([Remi-Gau](https://github.com/Remi-Gau)) - -## [v0.0.3](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/tree/v0.0.3) (2019-11-28) - -[Full Changelog](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/compare/v0.0.2...v0.0.3) - -**Merged pull requests:** - -- fix RFX issues and add credits - [\#60](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/60) - ([Remi-Gau](https://github.com/Remi-Gau)) - -## [v0.0.2](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/tree/v0.0.2) (2019-11-26) - -[Full Changelog](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/compare/v0.0.1...v0.0.2) - -**Merged pull requests:** - -- Create LICENSE - [\#58](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/58) - ([Remi-Gau](https://github.com/Remi-Gau)) -- fix problem when task JSON file is missing from root folder - [\#56](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/56) - ([Remi-Gau](https://github.com/Remi-Gau)) - -## [v0.0.1](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/tree/v0.0.1) (2019-11-13) - -[Full Changelog](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/compare/8ca4e1b47af1d983cde988bae1a9bd9659151330...v0.0.1) - -**Implemented enhancements:** - -- refactor getRuns, getSessions, getFilenames - [\#9](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/issues/9) -- find a way to specify the contrasts to compute - [\#11](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/issues/11) -- Complete boiler plate methods section of the README - [\#17](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/17) - ([Remi-Gau](https://github.com/Remi-Gau)) -- Big PR to fix previous PR, update FFX and RFX - [\#2](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/2) - ([Remi-Gau](https://github.com/Remi-Gau)) - -**Closed issues:** - -- spm_jsonread issue - [\#54](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/issues/54) -- \[WORKSHOP 2019\] - to do list - [\#48](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/issues/48) -- \[WORKSHOP 2019\] - MVPA - [\#47](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/issues/47) -- \[WORKSHOP 2019\] - sharing data - [\#46](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/issues/46) -- changes way subjects are indexed in getData - [\#44](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/issues/44) -- Add Moh as contributors - [\#37](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/issues/37) -- add Marco as contributors - [\#35](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/issues/35) -- getData issue with 2 groups - [\#22](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/issues/22) -- create a function to checks options and set some defaults if none are - specified - [\#15](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/issues/15) -- use SPM BIDS data set from SPM tuto to test and make a simple demo - [\#7](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/issues/7) -- test with octave - [\#5](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/issues/5) -- export final results as NIDM results to facilitate upload to neurovault - [\#52](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/issues/52) -- Consider to unzip the bold files in a separate function from BIDS_rmDumies.m - [\#26](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/issues/26) -- create a function that copies the raw data into a derivatives/SPM12-CPP - directory - [\#25](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/issues/25) - -**Merged pull requests:** - -- BIDS results - [\#55](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/55) - ([Remi-Gau](https://github.com/Remi-Gau)) -- \[WIP\] constrast specification + uni and multivaraite issues + remove - dummies [\#51](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/51) - ([Remi-Gau](https://github.com/Remi-Gau)) -- fix some details in getData to pass tests and make octave compatible - [\#45](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/45) - ([Remi-Gau](https://github.com/Remi-Gau)) -- fix indexing issue in getData - [\#43](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/43) - ([Remi-Gau](https://github.com/Remi-Gau)) -- docs: add OliColli as a contributor - [\#40](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/40) - ([allcontributors[bot]](https://github.com/apps/allcontributors)) -- docs: add anege as a contributor - [\#39](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/39) - ([allcontributors[bot]](https://github.com/apps/allcontributors)) -- docs: add mohmdrezk as a contributor - [\#38](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/38) - ([allcontributors[bot]](https://github.com/apps/allcontributors)) -- docs: add marcobarilari as a contributor - [\#36](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/36) - ([allcontributors[bot]](https://github.com/apps/allcontributors)) -- docs: add Remi-Gau as a contributor - [\#30](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/30) - ([allcontributors[bot]](https://github.com/apps/allcontributors)) -- Add another test to getData and improve README - [\#28](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/28) - ([Remi-Gau](https://github.com/Remi-Gau)) -- edit info about step1: 'Remove Dummy Scans' - [\#27](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/27) - ([marcobarilari](https://github.com/marcobarilari)) -- update doc - [\#24](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/24) - ([Remi-Gau](https://github.com/Remi-Gau)) -- - fix getData issue when there are multiple groups - [\#23](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/23) - ([mohmdrezk](https://github.com/mohmdrezk)) -- Ane getsessions merge - [\#19](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/19) - ([anege](https://github.com/anege)) -- Dockerfile and option defaults - [\#16](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/16) - ([Remi-Gau](https://github.com/Remi-Gau)) -- Containerization of the pipeline with docker and octave - [\#13](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/13) - ([Remi-Gau](https://github.com/Remi-Gau)) -- fix crash on batch_download_run - [\#12](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/12) - ([Remi-Gau](https://github.com/Remi-Gau)) -- Initial preparartion for Workshop scripts for Motion dataset - [\#10](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/10) - ([mohmdrezk](https://github.com/mohmdrezk)) -- delete extra getOptions - [\#8](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/8) - ([Remi-Gau](https://github.com/Remi-Gau)) -- Split into 3 repos - [\#1](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/pull/1) - ([Remi-Gau](https://github.com/Remi-Gau)) - -\* _This Changelog was automatically generated by -[github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)_ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 345742f1..88b79e16 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,3 +8,339 @@ is partly created using the bash script `createDummyDataSet.sh`. ## Changelog + + diff --git a/README.md b/README.md index d282e2c1..8ee55558 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ + + **Code quality and style** [![](https://img.shields.io/badge/Octave-CI-blue?logo=Octave&logoColor=white)](https://github.com/cpp-lln-lab/CPP_BIDS_SPM_pipeline/actions) @@ -20,6 +22,8 @@ + + # CPPL SPM12 Pipeline This is a set of functions to fMRI analysis on a @@ -28,18 +32,30 @@ This is a set of functions to fMRI analysis on a This can perform: - slice timing correction, + - spatial preprocessing: - - realignment, coregistration `func` to `anat`, `anat` segmention, + + - realignment, coregistration `func` to `anat`, `anat` segmentation, normalization to MNI space - - realignm and unwarp, coregistration `func` to `anat`, `anat` segmention + + - realignm and unwarp, coregistration `func` to `anat`, `anat` + segmentation + - smoothing, + - Quality analysis: + - for anatomical data - for functional data + - GLM at the subject level -- GLM at the group level à la SPM (meaning using a summary statistics approach). -Please see our [documentation](https://cpp-bids-spm.readthedocs.io/en/latest/index.html) for more info. +- GLM at the group level à la SPM (meaning using a summary statistics + approach). + +Please see our +[documentation](https://cpp-bids-spm.readthedocs.io/en/latest/index.html) for +more info. The core functions are in the `src` folder. @@ -52,6 +68,8 @@ path. For instructions see the following links: + + | Dependencies | Used version | | ----------------------------------------------------------------------------------------- | ------------ | | [Matlab](https://www.mathworks.com/products/matlab.html) | 20??? | @@ -60,14 +78,15 @@ For instructions see the following links: | [Tools for NIfTI and ANALYZE image toolbox](https://github.com/sergivalverde/nifti_tools) | NA | | [spmup](https://github.com/CPernet/spmup) | NA | + -## Contributors ✨ +## Contributors Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): - + @@ -77,7 +96,7 @@ Thanks goes to these wonderful people
OliColli
OliColli

💻 🎨 📖
Remi Gau
Remi Gau

💻 📖 🚇 🎨 👀
- + This project follows the diff --git a/demos/MoAE/MoAEpilot_run.m b/demos/MoAE/MoAEpilot_run.m index 641747ba..59e7c9b6 100644 --- a/demos/MoAE/MoAEpilot_run.m +++ b/demos/MoAE/MoAEpilot_run.m @@ -32,31 +32,31 @@ opt.space = 'individual'; %% Get data -% fprintf('%-40s:', 'Downloading dataset...'); -% urlwrite(URL, 'MoAEpilot.zip'); +fprintf('%-40s:', 'Downloading dataset...'); +urlwrite(URL, 'MoAEpilot.zip'); unzip('MoAEpilot.zip', fullfile(WD, 'output')); checkDependencies(); %% Run batches -% reportBIDS(opt); +reportBIDS(opt); +bidsCopyRawFolder(opt, 1); -% bidsCopyRawFolder(opt, 1); - -bidsSegmentSkullStrip(opt); - -return +% In case you just want to run segmentation and skull stripping +% bidsSegmentSkullStrip(opt); bidsSTC(opt); bidsSpatialPrepro(opt); -anatomicalQA(opt); -bidsResliceTpmToFunc(opt); -functionalQA(opt); +% The following do not run on octave for now (because of spmup) +% anatomicalQA(opt); +% bidsResliceTpmToFunc(opt); +% functionalQA(opt); bidsSmoothing(FWHM, opt); -bidsFFX('specifyAndEstimate', opt, FWHM); -bidsFFX('contrasts', opt, FWHM); -bidsResults(opt, FWHM); +% The following crash on Travis CI +% bidsFFX('specifyAndEstimate', opt, FWHM); +% bidsFFX('contrasts', opt, FWHM); +% bidsResults(opt, FWHM); diff --git a/demos/openneuro/ds000001_getOption.m b/demos/openneuro/ds000001_getOption.m index 07be6d40..6de06884 100644 --- a/demos/openneuro/ds000001_getOption.m +++ b/demos/openneuro/ds000001_getOption.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function opt = ds000001_getOption() % returns a structure that contains the options chosen by the user to run diff --git a/demos/openneuro/ds000001_run.m b/demos/openneuro/ds000001_run.m index c9201d39..a8b7f066 100644 --- a/demos/openneuro/ds000001_run.m +++ b/demos/openneuro/ds000001_run.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers % runDs00014 diff --git a/demos/openneuro/ds000114_getOption.m b/demos/openneuro/ds000114_getOption.m index 626aa34a..816f0561 100644 --- a/demos/openneuro/ds000114_getOption.m +++ b/demos/openneuro/ds000114_getOption.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function opt = ds000114_getOption() % returns a structure that contains the options chosen by the user to run diff --git a/demos/openneuro/ds000114_run.m b/demos/openneuro/ds000114_run.m index dc4b0424..c0fcbe27 100644 --- a/demos/openneuro/ds000114_run.m +++ b/demos/openneuro/ds000114_run.m @@ -1,10 +1,9 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers % runDs00014 clear; clc; -close all; % Smoothing to apply FWHM = 6; diff --git a/demos/openneuro/ds001168_getOption.m b/demos/openneuro/ds001168_getOption.m new file mode 100644 index 00000000..2f0ce7b8 --- /dev/null +++ b/demos/openneuro/ds001168_getOption.m @@ -0,0 +1,29 @@ +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers + +function opt = ds001168_getOption() + % 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/ds001168/raw'; + + % suject to run in each group + opt.subjects = {'01'}; + + % task to analyze + opt.taskName = 'rest'; + + opt.anatReference.type = 'T1w'; + opt.anatReference.session = 1; + + opt.ignoreFieldmaps = false; + + %% DO NOT TOUCH + opt = checkOptions(opt); + % saveOptions(opt); + +end diff --git a/demos/openneuro/ds001168_run.m b/demos/openneuro/ds001168_run.m new file mode 100644 index 00000000..305e1a10 --- /dev/null +++ b/demos/openneuro/ds001168_run.m @@ -0,0 +1,49 @@ +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers + +% runDs001168 + +clear; +clc; + +% Smoothing to apply +FWHM = 6; + +% directory with this script becomes the current directory +WD = fileparts(mfilename('fullpath')); + +% we add all the subfunctions that are in the sub directories +addpath(fullfile(WD, '..')); +addpath(genpath(fullfile(WD, '..', 'src'))); +addpath(genpath(fullfile(WD, '..', 'lib'))); + +%% Set options +opt = ds001168_getOption(); + +% the line below allows to run preprocessing in "native" space. +% - use realign and unwarp +% - don't do normalization +opt.space = 'individual'; + +checkDependencies(); + +%% Run batches + +reportBIDS(opt); + +bidsCopyRawFolder(opt, 1); + +bidsCreateVDM(opt); + +bidsSTC(opt); + +bidsSpatialPrepro(opt); + +anatomicalQA(opt); +bidsResliceTpmToFunc(opt); +functionalQA(opt); +% +% bidsSmoothing(FWHM, opt); +% +% bidsFFX('specifyAndEstimate', opt, FWHM); +% bidsFFX('contrasts', opt, FWHM); +% bidsResults(opt, FWHM, []); diff --git a/demos/openneuro/openneuro.md b/demos/openneuro/openneuro.md index fb80298d..c56643b6 100644 --- a/demos/openneuro/openneuro.md +++ b/demos/openneuro/openneuro.md @@ -1,13 +1,12 @@ - Download with datalad -In case you use the python package for datalad, activate your virtual environment (like conda). +In case you use the python package for datalad, activate your virtual +environment (like conda). ```bash conda activate datalad ``` - ## ds000114 Multi-subject and multi-session dataset. @@ -26,4 +25,16 @@ datalad get sub-0[12]/*/func/*linebisection* cd ds000001/ datalad get sub-0[12]/anat/*T1w* datalad get sub-0[12]/func/*balloonanalogrisktask* - ``` +``` + +## ds001168 + +7T test-retest data set with fieldmaps + +```bash + datalad clone https://github.com/OpenNeuroDatasets/ds001168.git + cd ds001168/ + datalad get sub-0[12]/ses*/anat/* + datalad get sub-0[12]/ses*/func/*fullbrain* + +``` diff --git a/docs/README.md b/docs/README.md index 93621c95..24a540c3 100644 --- a/docs/README.md +++ b/docs/README.md @@ -38,8 +38,8 @@ extensions = [ 'sphinx.ext.autodoc'] ``` -`matlab_src_dir` in `docs/source/conf.py` should have the path (relative to `conf.py`) -to the folder containing your matlab code: +`matlab_src_dir` in `docs/source/conf.py` should have the path (relative to +`conf.py`) to the folder containing your matlab code: ```python matlab_src_dir = os.path.dirname(os.path.abspath('../../src')) @@ -47,29 +47,42 @@ matlab_src_dir = os.path.dirname(os.path.abspath('../../src')) ## reStructured text markup -reStructured text mark up primers: +reStructured text mark up primers: -- on the [sphinx site](https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html) -- more [python oriented](https://pythonhosted.org/an_example_pypi_project/sphinx.html) +- on the [sphinx site](https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html) -- typical doc strings templates - - [google way](https://www.sphinx-doc.org/en/master/usage/extensions/example_google.html) - - [numpy](https://www.sphinx-doc.org/en/master/usage/extensions/example_numpy.html#example-numpy) +- more + [python oriented](https://pythonhosted.org/an_example_pypi_project/sphinx.html) + +- typical doc strings templates + - [google way](https://www.sphinx-doc.org/en/master/usage/extensions/example_google.html) + - [numpy](https://www.sphinx-doc.org/en/master/usage/extensions/example_numpy.html#example-numpy) ## "Templates" +The templates to use for the doc are in the `src/templates` folder. + You then just need to insert this in your `.rst` file for the documentation to be done automatically. ```rst -.. automodule:: src .. <-- This is necessary for autodocumenting the rest +.. automodule:: src.folder_name .. <-- This is necessary for auto-documenting the rest -.. autofunction:: my_function +.. autofunction:: function to document -.. autofunction:: my_function_napoleon ``` +To get the filenames of all the functions in a folder: + +``` bash +ls -l src/*.m | cut -c42- | rev | cut -c 3- | rev +``` + +Increase the `42` to crop more characters at the beginning. + +Change the `3` to crop more characters at the end. + ## Build the documentation locally From the `docs` directory: @@ -87,9 +100,9 @@ Add a [`.readthedocs.yml`](../.readthedocs.yml) file in the root of your repo. See [HERE](https://docs.readthedocs.io/en/stable/config-file/v2.html) for details. -You can then trigger the build of the doc by going to the [read the docs] -website: https://readthedocs.org. +You can then trigger the build of the doc by going to the +[read the docs website](https://readthedocs.org). You might need to be added as a maintainer of the doc. -The doc can be built from any branch of a repo. \ No newline at end of file +The doc can be built from any branch of a repo. diff --git a/docs/requirements.txt b/docs/requirements.txt index a4b9ccc8..42ea70da 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,4 +1,5 @@ Sphinx sphinxcontrib-matlabdomain sphinxcontrib-napoleon -sphinx_rtd_theme \ No newline at end of file +sphinx_rtd_theme +miss_hit \ No newline at end of file diff --git a/docs/source/batches.rst b/docs/source/batches.rst index 24cf0162..9da85ccb 100644 --- a/docs/source/batches.rst +++ b/docs/source/batches.rst @@ -7,18 +7,25 @@ List of functions to set SPM batches. .. automodule:: src.batches -.. autofunction:: setBatchCoregistration -.. autofunction:: setBatchNormalize -.. autofunction:: setBatchSegmentation +.. autofunction:: setBatchComputeVDM +.. autofunction:: setBatchCoregistrationFmap +.. autofunction:: setBatchCoregistrationFuncToAnat +.. autofunction:: setBatchCoregistration +.. autofunction:: setBatchCreateVDMs +.. autofunction:: setBatchFactorialDesign +.. autofunction:: setBatchImageCalculation +.. autofunction:: setBatchMeanAnatAndMask +.. autofunction:: setBatchNormalizationSpatialPrepro +.. autofunction:: setBatchNormalize +.. autofunction:: setBatchRealign +.. autofunction:: setBatchReslice +.. autofunction:: setBatchSaveCoregistrationMatrix +.. autofunction:: setBatchSegmentation +.. autofunction:: setBatchSelectAnat +.. autofunction:: setBatchSkullStripping +.. autofunction:: setBatchSmoothConImages +.. autofunction:: setBatchSmoothing .. autofunction:: setBatchSTC -.. autofunction:: setBatchFactorialDesign -.. autofunction:: setBatchRealign -.. autofunction:: setBatchSelectAnat .. autofunction:: setBatchSubjectLevelContrasts -.. autofunction:: setBatchMeanAnatAndMask -.. autofunction:: setBatchReslice -.. autofunction:: setBatchSmoothConImages -.. autofunction:: setBatchSubjectLevelGLMSpec -.. autofunction:: setBatchNormalizationSpatialPrepro -.. autofunction:: setBatchSaveCoregistrationMatrix -.. autofunction:: setBatchSmoothing \ No newline at end of file +.. autofunction:: setBatchSubjectLevelGLMSpec + \ No newline at end of file diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index 1b2439b6..d9855ed0 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -17,26 +17,26 @@ Template proposal % (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function [argout1, argout2] = templateFunction(argin1, argin2, argin3) - % - % Short description of what the function does goes here. - % - % USAGE: + % + % Short description of what the function does goes here. + % + % USAGE:: % % [argout1, argout2] = templateFunction(argin1, [argin2 == default,] [argin3]) % - % :param argin1: (dimension) obligatory argument. Lorem ipsum dolor sit amet, + % :param argin1: (dimension) obligatory argument. Lorem ipsum dolor sit amet, % consectetur adipiscing elit. Ut congue nec est ac lacinia. % :type argin1: type - % :param argin2: optional argument and its default value. And some of the + % :param argin2: optional argument and its default value. And some of the % options can be shown in litteral like ``this`` or ``that``. % :type argin2: string - % :param argin3: (dimension) optional argument + % :param argin3: (dimension) optional argument % - % :returns: - :argout1: (type) (dimension) - % - :argout2: (type) (dimension) + % :returns: - :argout1: (type) (dimension) + % - :argout2: (type) (dimension) % % .. todo: - % + % % - item 1 % - item 2 diff --git a/docs/source/defaults.rst b/docs/source/defaults.rst index 9956589a..85a1cc81 100644 --- a/docs/source/defaults.rst +++ b/docs/source/defaults.rst @@ -7,6 +7,10 @@ Defaults of the pipeline. .. automodule:: src.defaults +checkOptions +============ + +.. autofunction:: checkOptions spm_my_defaults =============== @@ -28,3 +32,4 @@ pipeline. .. autofunction:: spm_my_defaults + diff --git a/docs/source/function_description.rst b/docs/source/function_description.rst index 3ea62825..10745525 100644 --- a/docs/source/function_description.rst +++ b/docs/source/function_description.rst @@ -1,34 +1,76 @@ Function description -==================== +******************** List of functions in the ``src`` folder. ---- .. automodule:: src - -.. autofunction:: getBoldFilenameForFFX -.. autofunction:: getMeanFuncFilename -.. autofunction:: printProcessingRun -.. autofunction:: specifyContrasts -.. autofunction:: concatBetaImgTmaps -.. autofunction:: getBoldFilename -.. autofunction:: getPrefix -.. autofunction:: printProcessingSubject + +.. autofunction:: getAnatFilename +.. autofunction:: getBoldFilename +.. autofunction:: getData +.. autofunction:: getFuncVoxelDims +.. autofunction:: getInfo +.. autofunction:: getMeanFuncFilename +.. autofunction:: getPrefix +.. autofunction:: getRealignParamFile +.. autofunction:: getSliceOrder +.. autofunction:: getSpecificSubjects +.. autofunction:: setDerivativesDir .. autofunction:: unzipImgAndReturnsFullpathName -.. autofunction:: convertOnsetTsvToMat -.. autofunction:: getData -.. autofunction:: getRealignParamFile -.. autofunction:: createAndReturnOnsetFile -.. autofunction:: getFFXdir -.. autofunction:: getRFXdir -.. autofunction:: reportBIDS -.. autofunction:: getFuncVoxelDims -.. autofunction:: getSliceOrder -.. autofunction:: deleteResidualImages -.. autofunction:: getGrpLevelContrastToCompute -.. autofunction:: getSpecificSubjects + +Subject level model +=================== + +.. automodule:: src.subject_level + +.. autofunction:: concatBetaImgTmaps +.. autofunction:: convertOnsetTsvToMat +.. autofunction:: createAndReturnOnsetFile +.. autofunction:: deleteResidualImages +.. autofunction:: getBoldFilenameForFFX +.. autofunction:: getFFXdir +.. autofunction:: specifyContrasts + +Group level model +================= + +.. automodule:: src.group_level + +.. autofunction:: getGrpLevelContrastToCompute +.. autofunction:: getRFXdir + + +fieldmaps +========= + +.. automodule:: src.fieldmaps + +.. autofunction:: getBlipDirection +.. autofunction:: getMetadataFromIntendedForFunc +.. autofunction:: getTotalReadoutTime +.. autofunction:: getVdmFile + +Utilities +========= + +Utility functions + +---- + +.. automodule:: src.utils + +.. autofunction:: checkDependencies +.. autofunction:: createDataDictionary +.. autofunction:: getEnvInfo +.. autofunction:: getVersion +.. autofunction:: isOctave +.. autofunction:: loadAndCheckOptions +.. autofunction:: printCredits +.. autofunction:: printProcessingRun +.. autofunction:: printProcessingSubject .. autofunction:: saveMatlabBatch -.. autofunction:: getAnatFilename -.. autofunction:: getInfo -.. autofunction:: setDerivativesDir \ No newline at end of file +.. autofunction:: saveOptions +.. autofunction:: setDefaultFields +.. autofunction:: validationInputFile diff --git a/docs/source/index.rst b/docs/source/index.rst index a40529c8..aafb80c3 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -7,8 +7,8 @@ Welcome to CPP SPM BIDS pipeline documentation! *********************************************** .. toctree:: - :maxdepth: 3 - :caption: Contentset_up + :maxdepth: 2 + :caption: Content set_up workflows @@ -18,7 +18,6 @@ Welcome to CPP SPM BIDS pipeline documentation! function_description method_section_boilerplate mancoreg - utils docker contributing diff --git a/docs/source/method_section_boilerplate.rst b/docs/source/method_section_boilerplate.rst index bf90cbe6..aacb8fbc 100644 --- a/docs/source/method_section_boilerplate.rst +++ b/docs/source/method_section_boilerplate.rst @@ -1,6 +1,12 @@ Boilerplate methods section *************************** +Use the report function to get a print out of the content of a dataset. + +.. automodule:: src.reports + +.. autofunction:: reportBIDS + Preprocessing ============= diff --git a/docs/source/utils.rst b/docs/source/utils.rst deleted file mode 100644 index 3c67325f..00000000 --- a/docs/source/utils.rst +++ /dev/null @@ -1,22 +0,0 @@ -Utilities -========= - -Utilities functions - ----- - -.. automodule:: src.utils - -.. autofunction:: checkDependencies -.. autofunction:: createDataDictionary -.. autofunction:: getVersion -.. autofunction:: loadAndCheckOptions -.. autofunction:: saveOptions -.. autofunction:: validationInputFile -.. autofunction:: checkOptions -.. autofunction:: getEnvInfo -.. autofunction:: isOctave -.. autofunction:: printCredits -.. autofunction:: setDefaultFields - - diff --git a/docs/source/workflows.rst b/docs/source/workflows.rst index 0f6e6367..21f5872c 100644 --- a/docs/source/workflows.rst +++ b/docs/source/workflows.rst @@ -116,5 +116,7 @@ Comput results --- .. autofunction:: bidsRealignReslice - -.. autofunction:: bidsRealignUnwarp \ No newline at end of file +.. autofunction:: bidsRealignUnwarp +.. autofunction:: bidsCreateVDM +.. autofunction:: bidsResliceTpmToFunc +.. autofunction:: bidsSegmentSkullStrip diff --git a/getOption_template b/getOption_template deleted file mode 100644 index 15be3d13..00000000 --- a/getOption_template +++ /dev/null @@ -1,47 +0,0 @@ -function opt = getOption() -% returns a structure that contains the options chosen by the user to return -% the different workflows - -if nargin<1 - opt = []; -end - -% group of subjects to analyze -opt.groups = {''}; -% suject to run in each group -opt.subjects = {[]}; - -% task to analyze -opt.taskName = 'balloonanalogrisktask'; - -% The directory where the data are located -opt.dataDir = '/home/remi/BIDS/ds001/rawdata'; - -% Options for slice time correction -% If left unspecified the slice timing will be done using the mid-volume acquisition -% time point as reference. -% Slice order must be 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 here: https://en.wikibooks.org/wiki/SPM/Slice_Timing -opt.sliceOrder = []; -opt.STC_referenceSlice = []; - -% Options for normalize -% Voxel dimensions for resampling at normalization of functional data or leave empty [ ]. -opt.funcVoxelDims = []; - -% specify the model file that contains the contrasts to compute -opt.model.univariate.file = fullfile(fileparts(mfilename('fullpath')), 'model', model-balloonanalogriskUnivariate_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) ); - -end diff --git a/lib/bids-matlab b/lib/bids-matlab index dd04a370..cc946cf7 160000 --- a/lib/bids-matlab +++ b/lib/bids-matlab @@ -1 +1 @@ -Subproject commit dd04a3709dcbfd04255cd43ef1caced94872ddc8 +Subproject commit cc946cf7d63c5ad42aa7258ef4ef73a2d24c97e5 diff --git a/runTests.m b/runTests.m index ea84f508..ac531bf4 100644 --- a/runTests.m +++ b/runTests.m @@ -2,10 +2,6 @@ warning('OFF'); -addpath(fullfile(pwd, 'spm12')); -addpath(genpath(fullfile(pwd, 'src'))); -addpath(genpath(fullfile(pwd, 'lib'))); - spm('defaults', 'fMRI'); folderToCover = fullfile(pwd, 'src'); diff --git a/src/QA/anatomicalQA.m b/src/QA/anatomicalQA.m index 0c3eb686..c8336812 100644 --- a/src/QA/anatomicalQA.m +++ b/src/QA/anatomicalQA.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function anatomicalQA(opt) % anatomicalQA(opt) diff --git a/src/QA/functionalQA.m b/src/QA/functionalQA.m index baf04c41..ed016a9b 100644 --- a/src/QA/functionalQA.m +++ b/src/QA/functionalQA.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function functionalQA(opt) % functionalQA(opt) diff --git a/src/batches/setBatchComputeVDM.m b/src/batches/setBatchComputeVDM.m new file mode 100644 index 00000000..2c840c1b --- /dev/null +++ b/src/batches/setBatchComputeVDM.m @@ -0,0 +1,65 @@ +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers + +function matlabbatch = setBatchComputeVDM(matlabbatch, fmapType, refImage) + % matlabbatch = setBatchComputeVDM(type) + % + % adapted from spmup get_FM_workflow.m (@ commit + % 198c980d6d7520b1a996f0e56269e2ceab72cc83) + + switch lower(fmapType) + case 'phasediff' + matlabbatch{end + 1}.spm.tools.fieldmap.calculatevdm.subj(1).data.presubphasemag.phase = ''; + matlabbatch{end}.spm.tools.fieldmap.calculatevdm.subj(1).data.presubphasemag.magnitude = ''; + + case 'phase&mag' + matlabbatch{end}.spm.tools.fieldmap.calculatevdm.subj(1).data.phasemag.shortphase = ''; + matlabbatch{end}.spm.tools.fieldmap.calculatevdm.subj(1).data.phasemag.shortmag = ''; + matlabbatch{end}.spm.tools.fieldmap.calculatevdm.subj(1).data.phasemag.longphase = ''; + matlabbatch{end}.spm.tools.fieldmap.calculatevdm.subj(1).data.phasemag.longmag = ''; + + otherwise + error('This type of field map is not handled: %s', fmapType); + end + + UF = struct( ... + 'method', 'Mark3D', ... + 'fwhm', 10, ... + 'pad', 0, ... + 'ws', 1); + + MF = struct( ... + 'fwhm', 5, ... + 'nerode', 2, ... + 'ndilate', 4, ... + 'thresh', 0.5, ... + 'reg', 0.02); + + defaultsval = struct( ... + 'et', [NaN NaN], ... + 'maskbrain', 1, ... + 'blipdir', 1, ... + 'tert', '', ... + 'epifm', 0, ... % can be changed + 'ajm', 0, ... + 'uflags', UF, ... + 'mflags', MF); + + fieldMapTemplate = spm_select( ... + 'FPList', ... + fullfile( ... + spm('dir'), ... + 'toolbox', ... + 'FieldMap'), ... + '^T1.nii$'); + defaultsval.mflags.template = { fieldMapTemplate }; + + matlabbatch{end}.spm.tools.fieldmap.calculatevdm.subj(1).defaults.defaultsval = defaultsval; + + matlabbatch{end}.spm.tools.fieldmap.calculatevdm.subj(1).session.epi = {refImage}; + matlabbatch{end}.spm.tools.fieldmap.calculatevdm.subj(1).matchvdm = 1; + matlabbatch{end}.spm.tools.fieldmap.calculatevdm.subj(1).sessname = 'vdm-'; + matlabbatch{end}.spm.tools.fieldmap.calculatevdm.subj(1).writeunwarped = 1; + matlabbatch{end}.spm.tools.fieldmap.calculatevdm.subj(1).anat = ''; + matlabbatch{end}.spm.tools.fieldmap.calculatevdm.subj(1).matchanat = 0; + +end diff --git a/src/batches/setBatchCoregistration.m b/src/batches/setBatchCoregistration.m index a9438f8c..5cb17502 100644 --- a/src/batches/setBatchCoregistration.m +++ b/src/batches/setBatchCoregistration.m @@ -1,76 +1,14 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers - -function matlabbatch = setBatchCoregistration(matlabbatch, BIDS, subID, opt) - - fprintf(1, ' BUILDING SPATIAL JOB : COREGISTER\n'); - - matlabbatch{end + 1}.spm.spatial.coreg.estimate.ref(1) = ... - cfg_dep('Named File Selector: Anatomical(1) - Files', ... - substruct( ... - '.', 'val', '{}', {opt.orderBatches.selectAnat}, ... - '.', 'val', '{}', {1}, ... - '.', 'val', '{}', {1}, ... - '.', 'val', '{}', {1}), ... - substruct('.', 'files', '{}', {1})); - - % SOURCE IMAGE : DEPENDENCY FROM REALIGNEMENT - % Mean Image - - meanImageToUse = 'rmean'; - otherImageToUse = 'cfiles'; - if strcmp(opt.space, 'individual') - meanImageToUse = 'meanuwr'; - otherImageToUse = 'uwrfiles'; - end - - matlabbatch{end}.spm.spatial.coreg.estimate.source(1) = ... - cfg_dep('Realign: Estimate & Reslice/Unwarp: Mean Image', ... - substruct( ... - '.', 'val', '{}', {opt.orderBatches.realign}, ... - '.', 'val', '{}', {1}, ... - '.', 'val', '{}', {1}, ... - '.', 'val', '{}', {1}), ... - substruct('.', meanImageToUse)); - - % OTHER IMAGES : DEPENDENCY FROM REALIGNEMENT - - [sessions, nbSessions] = getInfo(BIDS, subID, opt, 'Sessions'); - - runCounter = 1; - - for iSes = 1:nbSessions - - % get all runs for that subject for this session - [~, nbRuns] = getInfo(BIDS, subID, opt, 'Runs', sessions{iSes}); - - for iRun = 1:nbRuns - - matlabbatch{end}.spm.spatial.coreg.estimate.other(runCounter) = ... - cfg_dep([ ... - 'Realign: Estimate & Reslice/Unwarp: Realigned Images (Sess ', ... - num2str(runCounter), ... - ')'], ... - substruct( ... - '.', 'val', '{}', {opt.orderBatches.realign}, ... - '.', 'val', '{}', {1}, ... - '.', 'val', '{}', {1}, ... - '.', 'val', '{}', {1}), ... - substruct( ... - '.', 'sess', '()', {runCounter}, ... - '.', otherImageToUse)); - - runCounter = runCounter + 1; - - end - - end - - % The following lines are commented out because those parameters - % can be set in the spm_my_defaults.m - % matlabbatch{end}.spm.spatial.coreg.estimate.eoptions.cost_fun = 'nmi'; - % matlabbatch{end}.spm.spatial.coreg.estimate.eoptions.sep = [4 2]; - % matlabbatch{end}.spm.spatial.coreg.estimate.eoptions.tol = ... - % [0.02 0.02 0.02 0.001 0.001 0.001 0.01 0.01 0.01 0.001 0.001 0.001]; - % matlabbatch{end}.spm.spatial.coreg.estimate.eoptions.fwhm = [7 7]; +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers + +function matlabbatch = setBatchCoregistration(matlabbatch, ref, src, other) + % matlabbatch = setBatchCoregistrationGeneral(matlabbatch, ref, src, other) + % + % ref: string + % src: string + % other: cell string + + matlabbatch{end + 1}.spm.spatial.coreg.estimate.ref = { ref }; + matlabbatch{end}.spm.spatial.coreg.estimate.source = { src }; + matlabbatch{end}.spm.spatial.coreg.estimate.other = other; end diff --git a/src/batches/setBatchCoregistrationFmap.m b/src/batches/setBatchCoregistrationFmap.m new file mode 100644 index 00000000..4e73a142 --- /dev/null +++ b/src/batches/setBatchCoregistrationFmap.m @@ -0,0 +1,53 @@ +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers + +function matlabbatch = setBatchCoregistrationFmap(BIDS, opt, subID) + + % TODO + % assumes all the fieldmap relate to the current task + % - use the "for" metadata field + % - implement for 'phase12', 'fieldmap', 'epi' + + fprintf(1, ' FIELDMAP WORKFLOW: COREGISTERING FIELD MAPS TO FIRST FUNC IMAGE\n'); + + % Create rough mean of the 1rst run to improve SNR for coregistration + % TODO use the slice timed EPI if STC was used ? + [sessions, nbSessions] = getInfo(BIDS, subID, opt, 'Sessions'); + runs = getInfo(BIDS, subID, opt, 'Runs', sessions{1}); + [fileName, subFuncDataDir] = getBoldFilename(BIDS, subID, sessions{1}, runs{1}, opt); + + spmup_basics(fullfile(subFuncDataDir, fileName), 'mean'); + + refImage = fullfile(subFuncDataDir, ['mean_', fileName]); + + matlabbatch = []; + + for iSes = 1:nbSessions + + runs = spm_BIDS(BIDS, 'runs', ... + 'modality', 'fmap', ... + 'sub', subID, ... + 'ses', sessions{iSes}); + + for iRun = 1:numel(runs) + + % TODO + % - Move to getInfo + fmapFiles = spm_BIDS(BIDS, 'data', ... + 'modality', 'fmap', ... + 'sub', subID, ... + 'ses', sessions{iSes}, ... + 'run', runs{iRun}); + + srcImage = strrep(fmapFiles{1}, 'phasediff', 'magnitude1'); + + otherImages = cell(2, 1); + otherImages{1} = strrep(fmapFiles{1}, 'phasediff', 'magnitude2'); + otherImages{2} = fmapFiles{1}; + + matlabbatch = setBatchCoregistration(matlabbatch, refImage, srcImage, otherImages); + + end + + end + +end diff --git a/src/batches/setBatchCoregistrationFuncToAnat.m b/src/batches/setBatchCoregistrationFuncToAnat.m new file mode 100644 index 00000000..40e11635 --- /dev/null +++ b/src/batches/setBatchCoregistrationFuncToAnat.m @@ -0,0 +1,76 @@ +% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers + +function matlabbatch = setBatchCoregistrationFuncToAnat(matlabbatch, BIDS, subID, opt) + + fprintf(1, ' BUILDING SPATIAL JOB : COREGISTER\n'); + + matlabbatch{end + 1}.spm.spatial.coreg.estimate.ref(1) = ... + cfg_dep('Named File Selector: Anatomical(1) - Files', ... + substruct( ... + '.', 'val', '{}', {opt.orderBatches.selectAnat}, ... + '.', 'val', '{}', {1}, ... + '.', 'val', '{}', {1}, ... + '.', 'val', '{}', {1}), ... + substruct('.', 'files', '{}', {1})); + + % SOURCE IMAGE : DEPENDENCY FROM REALIGNEMENT + % Mean Image + + meanImageToUse = 'rmean'; + otherImageToUse = 'cfiles'; + if strcmp(opt.space, 'individual') + meanImageToUse = 'meanuwr'; + otherImageToUse = 'uwrfiles'; + end + + matlabbatch{end}.spm.spatial.coreg.estimate.source(1) = ... + cfg_dep('Realign: Estimate & Reslice/Unwarp: Mean Image', ... + substruct( ... + '.', 'val', '{}', {opt.orderBatches.realign}, ... + '.', 'val', '{}', {1}, ... + '.', 'val', '{}', {1}, ... + '.', 'val', '{}', {1}), ... + substruct('.', meanImageToUse)); + + % OTHER IMAGES : DEPENDENCY FROM REALIGNEMENT + + [sessions, nbSessions] = getInfo(BIDS, subID, opt, 'Sessions'); + + runCounter = 1; + + for iSes = 1:nbSessions + + % get all runs for that subject for this session + [~, nbRuns] = getInfo(BIDS, subID, opt, 'Runs', sessions{iSes}); + + for iRun = 1:nbRuns + + matlabbatch{end}.spm.spatial.coreg.estimate.other(runCounter) = ... + cfg_dep([ ... + 'Realign: Estimate & Reslice/Unwarp: Realigned Images (Sess ', ... + num2str(runCounter), ... + ')'], ... + substruct( ... + '.', 'val', '{}', {opt.orderBatches.realign}, ... + '.', 'val', '{}', {1}, ... + '.', 'val', '{}', {1}, ... + '.', 'val', '{}', {1}), ... + substruct( ... + '.', 'sess', '()', {runCounter}, ... + '.', otherImageToUse)); + + runCounter = runCounter + 1; + + end + + end + + % The following lines are commented out because those parameters + % can be set in the spm_my_defaults.m + % matlabbatch{end}.spm.spatial.coreg.estimate.eoptions.cost_fun = 'nmi'; + % matlabbatch{end}.spm.spatial.coreg.estimate.eoptions.sep = [4 2]; + % matlabbatch{end}.spm.spatial.coreg.estimate.eoptions.tol = ... + % [0.02 0.02 0.02 0.001 0.001 0.001 0.01 0.01 0.01 0.001 0.001 0.001]; + % matlabbatch{end}.spm.spatial.coreg.estimate.eoptions.fwhm = [7 7]; + +end diff --git a/src/batches/setBatchCreateVDMs.m b/src/batches/setBatchCreateVDMs.m new file mode 100644 index 00000000..79d782df --- /dev/null +++ b/src/batches/setBatchCreateVDMs.m @@ -0,0 +1,119 @@ +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers + +function matlabbatch = setBatchCreateVDMs(BIDS, opt, subID) + % + % Short description of what the function does goes here. + % + % USAGE:: + % + % matlabbatch = setBatchCreateVDMs(BIDS, opt, subID) + % + % :param BIDS: + % :type BIDS: structure + % :param opt: + % :type opt: structure + % :param subID: + % + % :returns: - :matlabbatch: (structure) (dimension) + % + % TODO + % assumes all the fieldmap relate to the current task + % - implement for 'phase12', 'fieldmap', 'epi' + + fprintf(1, ' FIELDMAP WORKFLOW: CREATING VDMs \n'); + + [sessions, nbSessions] = getInfo(BIDS, subID, opt, 'Sessions'); + + runs = getInfo(BIDS, subID, opt, 'Runs', sessions{1}); + [fileName, subFuncDataDir] = getBoldFilename(BIDS, subID, sessions{1}, runs{1}, opt); + refImage = validationInputFile(subFuncDataDir, fileName, 'mean_'); + + matlabbatch = []; + for iSes = 1:nbSessions + + runs = spm_BIDS(BIDS, 'runs', ... + 'modality', 'fmap', ... + 'sub', subID, ... + 'ses', sessions{iSes}); + + for iRun = 1:numel(runs) + + matlabbatch = setBatchComputeVDM(matlabbatch, 'phasediff', refImage); + + % TODO + % Move to getInfo ? + fmapFiles = spm_BIDS(BIDS, 'data', ... + 'modality', 'fmap', ... + 'sub', subID, ... + 'ses', sessions{iSes}, ... + 'run', runs{iRun}); + + phaseImage = fmapFiles{1}; + matlabbatch{end}.spm.tools.fieldmap.calculatevdm.subj.data.presubphasemag.phase = ... + {phaseImage}; + + magnitudeImage = strrep(phaseImage, 'phasediff', 'magnitude1'); + matlabbatch{end}.spm.tools.fieldmap.calculatevdm.subj.data.presubphasemag.magnitude = ... + {magnitudeImage}; + + [echotimes, isEPI, totReadTime, blipDir] = getMetadataForVDM(BIDS, ... + subID, ... + sessions{iSes}, ... + runs{iRun}); + + matlabbatch{end}.spm.tools.fieldmap.calculatevdm.subj.defaults.defaultsval.et = echotimes; + matlabbatch{end}.spm.tools.fieldmap.calculatevdm.subj.defaults.defaultsval.tert = totReadTime; + matlabbatch{end}.spm.tools.fieldmap.calculatevdm.subj.defaults.defaultsval.blipdir = blipDir; + matlabbatch{end}.spm.tools.fieldmap.calculatevdm.subj.defaults.defaultsval.epifm = isEPI; + + end + + end + +end + +function varargout = getMetadataForVDM(BIDS, subID, sessionID, runID) + + % get metadata fmap and its associated func files + fmapMetadata = spm_BIDS(BIDS, 'metadata', ... + 'modality', 'fmap', ... + 'sub', subID, ... + 'ses', sessionID, ... + 'run', runID); + if numel(fmapMetadata) > 1 + fmapMetadata = fmapMetadata{1}; + end + + echotimes = getEchoTimes(fmapMetadata); + + isEPI = checkFmapPulseSequenceType(fmapMetadata); + + varargout{1} = echotimes; + varargout{2} = isEPI; + + [totalReadoutTime, blipDir] = getMetadataFromIntendedForFunc(BIDS, fmapMetadata); + + varargout{3} = totalReadoutTime; + varargout{4} = blipDir; + +end + +function echotimes = getEchoTimes(fmapMetadata) + + echotimes = 1000 * [ ... + fmapMetadata.EchoTime1, ... + fmapMetadata.EchoTime2]; % in milliseconds + +end + +function isEPI = checkFmapPulseSequenceType(fmapMetadata) + + isEPI = 0; + + if isfield(fmapMetadata, 'PulseSequenceType') && ... + sum(strfind(fmapMetadata.PulseSequenceType, 'EPI')) ~= 0 + + isEPI = 1; + end + +end diff --git a/src/batches/setBatchImageCalculation.m b/src/batches/setBatchImageCalculation.m new file mode 100644 index 00000000..076af5e4 --- /dev/null +++ b/src/batches/setBatchImageCalculation.m @@ -0,0 +1,16 @@ +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers + +function matlabbatch = setBatchImageCalculation(matlabbatch, input, output, outDir, expression) + + matlabbatch{end + 1}.spm.util.imcalc.input = input; + matlabbatch{end}.spm.util.imcalc.output = output; + matlabbatch{end}.spm.util.imcalc.outdir = { outDir }; + matlabbatch{end}.spm.util.imcalc.expression = expression; + + % matlabbatch{1}.spm.util.imcalc.var = struct('name', {}, 'value', {}); + % matlabbatch{1}.spm.util.imcalc.options.dmtx = 0; + % matlabbatch{1}.spm.util.imcalc.options.mask = 0; + % matlabbatch{1}.spm.util.imcalc.options.interp = 1; + % matlabbatch{1}.spm.util.imcalc.options.dtype = 4; + +end diff --git a/src/batches/setBatchRealign.m b/src/batches/setBatchRealign.m index cc6c9f33..7c9c5610 100644 --- a/src/batches/setBatchRealign.m +++ b/src/batches/setBatchRealign.m @@ -1,13 +1,35 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers -function [matlabbatch, voxDim] = setBatchRealign(matlabbatch, BIDS, subID, opt, action) - % [matlabbatch, voxDim] = setBatchRealign(matlabbatch, BIDS, subID, opt, action) +function [matlabbatch, voxDim] = setBatchRealign(varargin) % - % to set the batch in a spatial preprocessing pipeline + % Set the batch for realign / realign and reslice / realign and unwarp % - % Assumption about the order of the sessions: + % USAGE:: + % + % [matlabbatch, voxDim] = setBatchRealign(matlabbatch, BIDS, subID, opt, [action = 'realign']) + % + % :param matlabbatch: SPM batch + % :type matlabbatch: structure + % :param BIDS: BIDS layout returned by ``getData`` + % :type BIDS: structure + % :param subID: subject label + % :type subID: string + % :param opt: options + % :type opt: structure + % :param action: ``realign``, ``realignReslice``, ``realignUnwarp`` + % :type action: string + % + % :returns: - :matlabbatch: (structure) (dimension) + % - :voxDim: (array) (dimension) + + if numel(varargin) < 5 + [matlabbatch, BIDS, subID, opt] = deal(varargin{:}); + action = ''; + else + [matlabbatch, BIDS, subID, opt, action] = deal(varargin{:}); + end - if nargin < 5 || isempty(action) + if isempty(action) action = 'realign'; end @@ -44,18 +66,18 @@ for iRun = 1:nbRuns % get the filename for this bold run for this task - [fileName, subFuncDataDir] = getBoldFilename( ... - BIDS, ... - subID, ... - sessions{iSes}, ... - runs{iRun}, ... - opt); + [boldFilename, subFuncDataDir] = getBoldFilename( ... + BIDS, ... + subID, ... + sessions{iSes}, ... + runs{iRun}, ... + opt); % check that the file with the right prefix exist and we get and % save its voxeldimension prefix = getPrefix('preprocess', opt); - file = validationInputFile(subFuncDataDir, fileName, prefix); - [voxDim, opt] = getFuncVoxelDims(opt, subFuncDataDir, prefix, fileName); + file = validationInputFile(subFuncDataDir, boldFilename, prefix); + [voxDim, opt] = getFuncVoxelDims(opt, subFuncDataDir, prefix, boldFilename); if size(file, 1) > 1 errorStruct.identifier = 'setBatchRealign:tooManyFiles'; @@ -66,10 +88,15 @@ fprintf(1, ' %s\n', file); if strcmp(action, 'realignUnwarp') - matlabbatch{end}.spm.spatial.realignunwarp.data(1, runCounter).pmscan = ''; + + vdmFile = getVdmFile(BIDS, opt, boldFilename); + matlabbatch{end}.spm.spatial.realignunwarp.data(1, runCounter).pmscan = { vdmFile }; matlabbatch{end}.spm.spatial.realignunwarp.data(1, runCounter).scans = { file }; + else + matlabbatch{end}.spm.spatial.realign.estwrite.data{1, runCounter} = { file }; + end runCounter = runCounter + 1; diff --git a/src/batches/setBatchReslice.m b/src/batches/setBatchReslice.m index 3e270b8a..3de4a142 100644 --- a/src/batches/setBatchReslice.m +++ b/src/batches/setBatchReslice.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function matlabbatch = setBatchReslice(referenceImg, sourceImages) % matlabbatch = bidsSmoothing(referenceImg, sourceImages) diff --git a/src/batches/setBatchSaveCoregistrationMatrix.m b/src/batches/setBatchSaveCoregistrationMatrix.m index 78ab40da..99e70647 100644 --- a/src/batches/setBatchSaveCoregistrationMatrix.m +++ b/src/batches/setBatchSaveCoregistrationMatrix.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function matlabbatch = setBatchSaveCoregistrationMatrix(matlabbatch, BIDS, subID, opt) diff --git a/src/defaults/checkOptions.m b/src/defaults/checkOptions.m index c840ad0c..952d34cd 100644 --- a/src/defaults/checkOptions.m +++ b/src/defaults/checkOptions.m @@ -88,6 +88,11 @@ fieldsToSet.STC_referenceSlice = []; % reference slice: middle acquired slice fieldsToSet.sliceOrder = []; % To be used if SPM can't extract slice info + % when opt.ignoreFieldmaps is set to false, the + % preprocessing pipeline will look for the voxel displacement maps (created by + % the corresponding workflow) and will use them for realign and unwarp + fieldsToSet.ignoreFieldmaps = false; + % fieldsToSet for normalize % Voxel dimensions for resampling at normalization of functional data or leave empty [ ]. fieldsToSet.funcVoxelDims = []; diff --git a/src/fieldmaps/getBlipDirection.m b/src/fieldmaps/getBlipDirection.m new file mode 100644 index 00000000..0212f7c6 --- /dev/null +++ b/src/fieldmaps/getBlipDirection.m @@ -0,0 +1,37 @@ +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers + +function blipDir = getBlipDirection(metadata) + % + % Gets the total read out time of a sequence. + % + % USAGE:: + % + % blipDir = getBlipDirection(metadata) + % + % :param metadata: image metadata + % :type metadata: strcuture + % + % :returns: - :blipDir: + % + % Used to create the voxel dsiplacement map (VDM) from the fieldmap + % + + blipDir = 1; + + if isfield(metadata, 'PhaseEncodingDirection') && ... + ~isempty(metadata.PhaseEncodingDirection) + + switch metadata.PhaseEncodingDirection + + case {'i', 'j', 'y'} + blipDir = 1; + case {'i-', 'j-', 'y-'} + blipDir = -1; + otherwise + error('unknown phase encoding direction: %s', metadata.PhaseEncodingDirection); + + end + + end + +end diff --git a/src/fieldmaps/getMetadataFromIntendedForFunc.m b/src/fieldmaps/getMetadataFromIntendedForFunc.m new file mode 100644 index 00000000..e0b28830 --- /dev/null +++ b/src/fieldmaps/getMetadataFromIntendedForFunc.m @@ -0,0 +1,63 @@ +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers + +function [totalReadoutTime, blipDir] = getMetadataFromIntendedForFunc(BIDS, fmapMetadata) + % get metadata of the associated bold file + % find bold file this fmap is intended for, parse its filename and get its + % metadata + % + % USAGE:: + % + % [totalReadoutTime, blipDir] = getMetadataFromIntendedForFunc(BIDS, fmapMetadata) + % + % :param BIDS: + % :type BIDS: structure + % :param fmapMetadata: + % :type fmapMetadata: structure + % + % :returns: - :totalReadoutTime: (type) (dimension) + % - :blipDir: (type) (dimension) + % + % At the moment the VDM is created based on the characteristics of the last + % func file in the IntendedFor field + % + % TODO + % - if there are several func file for this fmap and they have different + % characteristic this may require creating a VDM for each + + for iFile = 1:size(fmapMetadata.IntendedFor) + + if iscell(fmapMetadata.IntendedFor) + filename = fmapMetadata.IntendedFor{iFile}; + else + filename = fmapMetadata.IntendedFor(iFile, :); + end + filename = spm_file(filename, 'filename'); + + fragments = bids.internal.parse_filename(filename); + + funcMetadata = spm_BIDS(BIDS, 'metadata', ... + 'modality', 'func', ... + 'type', fragments.type, ... + 'sub', fragments.sub, ... + 'ses', fragments.ses, ... + 'run', fragments.run, ... + 'acq', fragments.acq); + + end + + totalReadoutTime = getTotalReadoutTime(funcMetadata); + + % temporary for designing + % totalReadoutTime = 63; + + if isempty(totalReadoutTime) + errorStruct.identifier = 'getMetadataForVDM:emptyReadoutTime'; + errorStruct.message = [ ... + 'Voxel displacement map creation requires a non empty value' ... + 'for the TotalReadoutTime of the bold sequence they are matched to.']; + error(errorStruct); + end + + blipDir = getBlipDirection(funcMetadata); + +end diff --git a/src/fieldmaps/getTotalReadoutTime.m b/src/fieldmaps/getTotalReadoutTime.m new file mode 100644 index 00000000..b4c7770b --- /dev/null +++ b/src/fieldmaps/getTotalReadoutTime.m @@ -0,0 +1,66 @@ +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers + +function totalReadoutTime = getTotalReadoutTime(metadata) + % + % Gets the total read out time of a sequence. + % + % USAGE:: + % + % totalReadoutTime = getTotalReadoutTime(metadata) + % + % :param metadata: image metadata + % :type metadata: strcuture + % + % :returns: - :totalReadoutTime: (float) in millisecond + % + % Used to create the voxel dsiplacement map (VDM) from the fieldmap + % + + totalReadoutTime = ''; + + % apparently this comes from the functional metadata to create the VDM + if isfield(metadata, 'TotalReadoutTime') && ~isempty(metadata.TotalReadoutTime) + totalReadoutTime = metadata.TotalReadoutTime; + + % TODO + % double check this section + % this was in spmup but I don't remember where I got this from + % + % % from spmup: apparently this comes from the fmap metadata + % % but PixelBandwidth is not is not a valid BIDS term + % elseif isfield(metadata, 'PixelBandwidth') && ~isempty(metadata.PixelBandwidth) + % totalReadoutTime = 1 / fieldmap_param.PixelBandwidth * 1000; + % warning('PixelBandwidth is not a valid BIDS term.'); + % + % % apparently this comes from the functional metadata ??? + % elseif isfield(metadata, 'RepetitionTime') && ~isempty(metadata.RepetitionTime) + % totalReadoutTime = metadata.RepetitionTime; + % + % % apparently this comes from the functional metadata ??? + % elseif isfield(metadata, 'EffectiveEchoSpacing') && ~isempty(metadata.NumberOfEchos) + % totalReadoutTime = (metadata.NumberOfEchos - 1) * ... + % metadata.EffectiveEchoSpacing; + + %% Phase enconded lines (PELines) and ReadOutTime + + % PELines = ((BaseResolution * PartialFourier)/iPat) + ((iPat-1)/iPAT) * ReferenceLines) = + % ReadoutDuration = PELines * InterEchoSpacing + + % GRAPPA=iPAT4 ; Partial Fourrier=6/8 ; 48 sli ; TE=25ms ; Res=0.75 mm + % Bandwidth Per Pixel Phase Encode = 15.873 + + %% According to Robert Trampel + + % For distortion correction: ignore Partial Fourrier and references lines + % BaseResolution/iPAT = PELines + + % Effective echo spacing: 2 ways to calculate, should be the same + % 1/(Bandwidth Per Pixel Phase Encode * Reconstructed phase lines) --> 0.246 ms + % echo spacing (syngo) / iPAT + + % SPM Total readout time = 1/"Bandwidth Per Pixel Phase Encode", stored in + % DICOM tag (0019, 1028) --> 63 ms + + end + +end diff --git a/src/fieldmaps/getVdmFile.m b/src/fieldmaps/getVdmFile.m new file mode 100644 index 00000000..8c57dfb0 --- /dev/null +++ b/src/fieldmaps/getVdmFile.m @@ -0,0 +1,67 @@ +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers + +function vdmFile = getVdmFile(BIDS, opt, boldFilename) + % + % returns the voxel displacement map associated with a given bold file + % + % USAGE:: + % + % vdmFile = getVdmFile(BIDS, opt, boldFilename) + % + % :param BIDS: + % :type BIDS: structure + % :param opt: options + % :type opt: structure + % :param boldFilename: + % :type opt: string + % + % :returns: - :vdmFile: (string) + % + + vdmFile = ''; + + fragments = bids.internal.parse_filename(boldFilename); + + if ~isfield(fragments, 'ses') + fragments.ses = ''; + end + + modalities = spm_BIDS(BIDS, 'modalities', ... + 'sub', fragments.sub, ... + 'ses', fragments.ses); + + if ~opt.ignoreFieldmaps && any(ismember('fmap', modalities)) + % We loop through the field maps and find the one that is intended for this + % bold file by reading from the metadata + % + % We break the loop when the file has been found + + fmapFiles = spm_BIDS(BIDS, 'data', ... + 'modality', 'fmap', ... + 'sub', fragments.sub, ... + 'ses', fragments.ses); + + fmapMetadata = spm_BIDS(BIDS, 'metadata', ... + 'modality', 'fmap', ... + 'sub', fragments.sub, ... + 'ses', fragments.ses); + + for iFile = 1:size(fmapFiles, 1) + + intendedFor = fmapMetadata{iFile}.IntendedFor; + + if strfind(intendedFor, boldFilename) %#ok + [pth, filename, ext] = spm_fileparts(fmapFiles{iFile}); + vdmFile = validationInputFile(pth, [filename ext], 'vdm5_sc'); + break + end + + end + + end + + if isempty(vdmFile) + warning('No voxel displacement map associated with: \n %s', boldFilename); + end + +end diff --git a/src/getAnatFilename.m b/src/getAnatFilename.m index 75a2305d..66a6cc9b 100644 --- a/src/getAnatFilename.m +++ b/src/getAnatFilename.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function [anatImage, anatDataDir] = getAnatFilename(BIDS, subID, opt) % [anatImage, anatDataDir] = getAnatFilename(BIDS, subID, opt) diff --git a/src/getData.m b/src/getData.m index b1a0068c..f7656b37 100644 --- a/src/getData.m +++ b/src/getData.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function [group, opt, BIDS] = getData(opt, BIDSdir, type) % [group, opt, BIDS] = getData(opt, BIDSdir, type) diff --git a/src/getFuncVoxelDims.m b/src/getFuncVoxelDims.m index c1192aad..d5fe3851 100644 --- a/src/getFuncVoxelDims.m +++ b/src/getFuncVoxelDims.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function [voxDim, opt] = getFuncVoxelDims(opt, subFuncDataDir, prefix, fileName) % [voxDim, opt] = getFuncVoxelDims(opt, subFuncDataDir, prefix, fileName) diff --git a/src/getInfo.m b/src/getInfo.m index 98ca7b69..dd4a8626 100644 --- a/src/getInfo.m +++ b/src/getInfo.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function varargout = getInfo(BIDS, subID, opt, info, varargin) % wrapper function to fetch specific info in a BIDS structure returned by @@ -70,14 +70,12 @@ [session, run, type] = deal(varargin{:}); - fileName = spm_BIDS(BIDS, 'data', ... - 'sub', subID, ... - 'run', run, ... - 'ses', session, ... - 'task', opt.taskName, ... - 'type', type); - - varargout = fileName; + varargout = spm_BIDS(BIDS, 'data', ... + 'sub', subID, ... + 'run', run, ... + 'ses', session, ... + 'task', opt.taskName, ... + 'type', type); otherwise error('Not sure what info you want me to get.'); diff --git a/src/getMeanFuncFilename.m b/src/getMeanFuncFilename.m index 8641a492..72a7459e 100644 --- a/src/getMeanFuncFilename.m +++ b/src/getMeanFuncFilename.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function [meanImage, meanFuncDir] = getMeanFuncFilename(BIDS, subID, opt) % [anatImage, anatDataDir] = getAnatFilename(BIDS, subID, opt) diff --git a/src/getPrefix.m b/src/getPrefix.m index 9f4776c0..2314b8d8 100644 --- a/src/getPrefix.m +++ b/src/getPrefix.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function [prefix, motionRegressorPrefix] = getPrefix(step, opt, funcFWHM) % [prefix, motionRegressorPrefix] = getPrefix(step, opt, funcFWHM) diff --git a/src/getRealignParamFile.m b/src/getRealignParamFile.m index 7f743072..c4347b70 100644 --- a/src/getRealignParamFile.m +++ b/src/getRealignParamFile.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function realignParamFile = getRealignParamFile(fullpathBoldFileName, prefix) diff --git a/src/getSliceOrder.m b/src/getSliceOrder.m index 2c164165..37449801 100644 --- a/src/getSliceOrder.m +++ b/src/getSliceOrder.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function sliceOrder = getSliceOrder(opt, verbose) % get the slice order information from the BIDS data set or from getOption diff --git a/src/getSpecificSubjects.m b/src/getSpecificSubjects.m index 15d9f1c7..af259063 100644 --- a/src/getSpecificSubjects.m +++ b/src/getSpecificSubjects.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function group = getSpecificSubjects(opt, group, iGroup, subjects) diff --git a/src/getGrpLevelContrastToCompute.m b/src/group_level/getGrpLevelContrastToCompute.m similarity index 100% rename from src/getGrpLevelContrastToCompute.m rename to src/group_level/getGrpLevelContrastToCompute.m diff --git a/src/getRFXdir.m b/src/group_level/getRFXdir.m similarity index 100% rename from src/getRFXdir.m rename to src/group_level/getRFXdir.m diff --git a/src/mancoreg/mancoreg.m b/src/mancoreg/mancoreg.m index e4e2d99d..d2cf31e7 100644 --- a/src/mancoreg/mancoreg.m +++ b/src/mancoreg/mancoreg.m @@ -1,7 +1,7 @@ % (C) Copyright 2004-2009 JH % (C) Copyright 2009_2012 DSS % (C) Copyright 2012_2019 Remi Gau -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function mancoreg(targetimage, sourceimage) % mancoreg(targetimage, sourceimage) diff --git a/src/mancoreg/mancoregCallbacks.m b/src/mancoreg/mancoregCallbacks.m index 32f42b63..f1bb63f0 100644 --- a/src/mancoreg/mancoregCallbacks.m +++ b/src/mancoreg/mancoregCallbacks.m @@ -1,7 +1,7 @@ % (C) Copyright 2004-2009 JH % (C) Copyright 2009_2012 DSS % (C) Copyright 2012_2019 Remi Gau -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function mancoregCallbacks(operation, varargin) % mancoreg_callbacks(op, varargin) diff --git a/src/reportBIDS.m b/src/reports/reportBIDS.m similarity index 100% rename from src/reportBIDS.m rename to src/reports/reportBIDS.m diff --git a/src/setDerivativesDir.m b/src/setDerivativesDir.m index 6ee46fa3..3012c175 100644 --- a/src/setDerivativesDir.m +++ b/src/setDerivativesDir.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function opt = setDerivativesDir(opt) % derivativeDir sets the derivatives folder diff --git a/src/concatBetaImgTmaps.m b/src/subject_level/concatBetaImgTmaps.m similarity index 100% rename from src/concatBetaImgTmaps.m rename to src/subject_level/concatBetaImgTmaps.m diff --git a/src/convertOnsetTsvToMat.m b/src/subject_level/convertOnsetTsvToMat.m similarity index 100% rename from src/convertOnsetTsvToMat.m rename to src/subject_level/convertOnsetTsvToMat.m diff --git a/src/createAndReturnOnsetFile.m b/src/subject_level/createAndReturnOnsetFile.m similarity index 100% rename from src/createAndReturnOnsetFile.m rename to src/subject_level/createAndReturnOnsetFile.m diff --git a/src/deleteResidualImages.m b/src/subject_level/deleteResidualImages.m similarity index 100% rename from src/deleteResidualImages.m rename to src/subject_level/deleteResidualImages.m diff --git a/src/getBoldFilenameForFFX.m b/src/subject_level/getBoldFilenameForFFX.m similarity index 94% rename from src/getBoldFilenameForFFX.m rename to src/subject_level/getBoldFilenameForFFX.m index a87aa925..d0c5b42a 100644 --- a/src/getBoldFilenameForFFX.m +++ b/src/subject_level/getBoldFilenameForFFX.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function [boldFileName, prefix] = getBoldFilenameForFFX(varargin) % [boldFileName, prefix] = getBoldFilenameForFFX(BIDS, opt, subID, funcFWHM, iSes, iRun) diff --git a/src/getFFXdir.m b/src/subject_level/getFFXdir.m similarity index 100% rename from src/getFFXdir.m rename to src/subject_level/getFFXdir.m diff --git a/src/specifyContrasts.m b/src/subject_level/specifyContrasts.m similarity index 100% rename from src/specifyContrasts.m rename to src/subject_level/specifyContrasts.m diff --git a/src/templates/templateFunction.m b/src/templates/templateFunction.m index bf349d86..4b6135cc 100644 --- a/src/templates/templateFunction.m +++ b/src/templates/templateFunction.m @@ -1,29 +1,29 @@ % (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function [argout1, argout2] = templateFunction(argin1, argin2, argin3) - % - % Short description of what the function does goes here. - % - % USAGE: - % - % [argout1, argout2] = templateFunction(argin1, [argin2 == default,] [argin3]) - % - % :param argin1: (dimension) obligatory argument. Lorem ipsum dolor sit amet, - % consectetur adipiscing elit. Ut congue nec est ac lacinia. - % :type argin1: type - % :param argin2: optional argument and its default value. And some of the - % options can be shown in litteral like ``this`` or ``that``. - % :type argin2: string - % :param argin3: (dimension) optional argument - % - % :returns: - :argout1: (type) (dimension) - % - :argout2: (type) (dimension) - % - % .. todo: - % - % - item 1 - % - item 2 + % + % Short description of what the function does goes here. + % + % USAGE:: + % + % [argout1, argout2] = templateFunction(argin1, [argin2 == default,] [argin3]) + % + % :param argin1: (dimension) obligatory argument. Lorem ipsum dolor sit amet, + % consectetur adipiscing elit. Ut congue nec est ac lacinia. + % :type argin1: type + % :param argin2: optional argument and its default value. And some of the + % options can be shown in litteral like ``this`` or ``that``. + % :type argin2: string + % :param argin3: (dimension) optional argument + % + % :returns: - :argout1: (type) (dimension) + % - :argout2: (type) (dimension) + % + % .. todo: + % + % - item 1 + % - item 2 - % The code goes below + % The code goes below -end \ No newline at end of file +end diff --git a/src/templates/templateFunctionExample.m b/src/templates/templateFunctionExample.m index 0ce1dec7..e4a39d6d 100644 --- a/src/templates/templateFunctionExample.m +++ b/src/templates/templateFunctionExample.m @@ -1,42 +1,42 @@ % (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function templateFunctionExample() - % This function illustrates a documentation test defined for MOdox. - % Other than that it does absolutely nothinghort description of what - % the function does goes here. - % - % Examples: - % a=2; - % disp(a) - % % Expected output is prefixed by '%||' as in the following line: - % %|| 2 - % % - % % The test continues because no interruption through whitespace, - % % as the previous line used a '%' comment character; - % % thus the 'a' variable is still in the namespace and can be - % % accessed. - % b=3+a; - % disp(a+[3 4]) - % %|| [5 6] - % - % % A new test starts here because the previous line was white-space - % % only. Thus the 'a' and 'b' variables are not present here anymore. - % % The following expression raises an error because the 'b' variable - % % is not defined (and does not carry over from the previous test). - % % Because the expected output indicates an error as well, - % % the test passes - % disp(b) - % %|| error('Some error') - % - % % A set of expressions is ignored if there is no expected output - % % (that is, no lines starting with '%||'). - % % Thus, the following expression is not part of any test, - % % and therefore does not raise an error. - % error('this is never executed) - % - % - % % tests end here because test indentation has ended + % This function illustrates a documentation test defined for MOdox. + % Other than that it does absolutely nothinghort description of what + % the function does goes here. + % + % Examples: + % a=2; + % disp(a) + % % Expected output is prefixed by '%||' as in the following line: + % %|| 2 + % % + % % The test continues because no interruption through whitespace, + % % as the previous line used a '%' comment character; + % % thus the 'a' variable is still in the namespace and can be + % % accessed. + % b=3+a; + % disp(a+[3 4]) + % %|| [5 6] + % + % % A new test starts here because the previous line was white-space + % % only. Thus the 'a' and 'b' variables are not present here anymore. + % % The following expression raises an error because the 'b' variable + % % is not defined (and does not carry over from the previous test). + % % Because the expected output indicates an error as well, + % % the test passes + % disp(b) + % %|| error('Some error') + % + % % A set of expressions is ignored if there is no expected output + % % (that is, no lines starting with '%||'). + % % Thus, the following expression is not part of any test, + % % and therefore does not raise an error. + % error('this is never executed) + % + % + % % tests end here because test indentation has ended - % The code goes below + % The code goes below -end \ No newline at end of file +end diff --git a/src/templates/templateFunctionNumpy.m b/src/templates/templateFunctionNumpy.m index 77cb0e67..ff449f9d 100644 --- a/src/templates/templateFunctionNumpy.m +++ b/src/templates/templateFunctionNumpy.m @@ -1,21 +1,21 @@ % (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function [argout] = templateFunctionNumpy(argin1, argin2, argin3) - % - % Short description of what the function does goes here. - % - % y = templateFunction(argin1, argin2, argin3) - % - % Parameters: - % argin1: The first input value - % - % argin2: The second input value - % - % argin3: The third input value - % - % Returns: - % The input value multiplied by two + % + % Short description of what the function does goes here. + % + % y = templateFunction(argin1, argin2, argin3) + % + % Parameters: + % argin1: The first input value + % + % argin2: The second input value + % + % argin3: The third input value + % + % Returns: + % The input value multiplied by two - % The code goes below + % The code goes below -end \ No newline at end of file +end diff --git a/src/templates/templateGetOption.m b/src/templates/templateGetOption.m new file mode 100644 index 00000000..b1eb5872 --- /dev/null +++ b/src/templates/templateGetOption.m @@ -0,0 +1,71 @@ +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers + +function opt = templateGetOption() + % returns a structure that contains the options chosen by the user to return + % the different workflows + + if nargin < 1 + opt = []; + end + + % group of subjects to analyze + % opt.groups = {''}; + % suject to run in each group + % opt.subjects = {[]}; + + % task to analyze + opt.taskName = 'balloonanalogrisktask'; + + % The directory where the data are located + opt.dataDir = '/home/remi/BIDS/ds001/rawdata'; + + % Where the data will go + % opt.derivativesDir = ''; + + % Options for slice time correction + % If left unspecified the slice timing will be done using the mid-volume acquisition + % time point as reference. + % Slice order must be 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 here: https://en.wikibooks.org/wiki/SPM/Slice_Timing + % opt.sliceOrder = []; + % opt.STC_referenceSlice = []; + + % when opt.ignoreFieldmaps is set to false, the + % preprocessing pipeline will look for the voxel displacement maps (created by + % the corresponding workflow) and will use them for realign and unwarp + % opt.ignoreFieldmaps = false; + + % session number and type of the anatomical reference + % opt.anatReference.type = 'T1w'; + % opt.anatReference.session = 1; + + % any voxel with p(grayMatter) + p(whiteMatter) + p(CSF) > threshold + % will be included in the skull stripping mask + % opt.skullstrip.threshold = 0.75; + + % space where we conduct the analysis + % opt.space = 'MNI'; + + % Options for normalize + % Voxel dimensions for resampling at normalization of functional data or leave empty [ ]. + % opt.funcVoxelDims = []; + + % specify the model file that contains the contrasts to compute + opt.model.univariate.file = ... + fullfile(fileparts(mfilename('fullpath')), ... + 'model', ... + 'model - balloonanalogriskUnivariate_smdl.json'); + + % specify the result to compute + % opt.result.Steps(1) = struct( ... + % 'Level', 'dataset', ... + % 'Contrasts', struct( ... + % 'Name', 'pumps_demean', ... + % 'Mask', false, ... + % 'MC', 'none', ... FWE, none, FDR + % 'p', 0.05, ... + % 'k', 0, ... + % 'NIDM', true)); + +end diff --git a/src/unzipImgAndReturnsFullpathName.m b/src/unzipImgAndReturnsFullpathName.m index 42116cd7..d13bed94 100644 --- a/src/unzipImgAndReturnsFullpathName.m +++ b/src/unzipImgAndReturnsFullpathName.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function unzippedFullpathImgName = unzipImgAndReturnsFullpathName(fullpathImgName) % unzippedFullpathImgName = unzipImgAndReturnsFullpathName(fullpathImgName) diff --git a/src/utils/createDataDictionary.m b/src/utils/createDataDictionary.m index c58db070..454f6edb 100644 --- a/src/utils/createDataDictionary.m +++ b/src/utils/createDataDictionary.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function createDataDictionary(subFuncDataDir, fileName, nbColums) diff --git a/src/utils/loadAndCheckOptions.m b/src/utils/loadAndCheckOptions.m index 3c3b79b6..619b497a 100644 --- a/src/utils/loadAndCheckOptions.m +++ b/src/utils/loadAndCheckOptions.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function opt = loadAndCheckOptions(opt) % opt = loadAndCheckOptions(opt) @@ -19,6 +19,7 @@ return end + % finds most recent option file if size(opt, 1) > 1 containsDate = cellfun(@any, strfind(cellstr(opt), '_date-')); opt = opt(containsDate, :); diff --git a/src/printProcessingRun.m b/src/utils/printProcessingRun.m similarity index 89% rename from src/printProcessingRun.m rename to src/utils/printProcessingRun.m index dbab8a53..d0b3efba 100644 --- a/src/printProcessingRun.m +++ b/src/utils/printProcessingRun.m @@ -4,7 +4,7 @@ function printProcessingRun(groupName, iSub, subID, iSes, iRun) fprintf(1, ... [ ... - 'PROCESSING GROUP: %s' ... + ' PROCESSING GROUP: %s' ... 'SUBJECT No.: %i ' ... 'SUBJECT ID : %s ' ... 'SESSION: %i ' ... diff --git a/src/printProcessingSubject.m b/src/utils/printProcessingSubject.m similarity index 85% rename from src/printProcessingSubject.m rename to src/utils/printProcessingSubject.m index 308ad32a..61e4a00a 100644 --- a/src/printProcessingSubject.m +++ b/src/utils/printProcessingSubject.m @@ -3,7 +3,7 @@ function printProcessingSubject(groupName, iSub, subID) fprintf(1, [ ... - 'PROCESSING GROUP: %s' ... + ' PROCESSING GROUP: %s' ... 'SUBJECT No.: %i ' ... 'SUBJECT ID : %s \n'], ... groupName, iSub, subID); diff --git a/src/saveMatlabBatch.m b/src/utils/saveMatlabBatch.m similarity index 100% rename from src/saveMatlabBatch.m rename to src/utils/saveMatlabBatch.m diff --git a/src/utils/saveOptions.m b/src/utils/saveOptions.m index dff2d99b..4d912caa 100644 --- a/src/utils/saveOptions.m +++ b/src/utils/saveOptions.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function saveOptions(opt) diff --git a/src/utils/setDefaultFields.m b/src/utils/setDefaultFields.m index 666ea7b6..98689d7d 100644 --- a/src/utils/setDefaultFields.m +++ b/src/utils/setDefaultFields.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function structure = setDefaultFields(structure, fieldsToSet) % structure = setDefaultFields(structure, fieldsToSet) diff --git a/src/workflows/bidsCopyRawFolder.m b/src/workflows/bidsCopyRawFolder.m index 7a921091..6f059559 100644 --- a/src/workflows/bidsCopyRawFolder.m +++ b/src/workflows/bidsCopyRawFolder.m @@ -1,58 +1,54 @@ % (C) Copyright 2019 CPP BIDS SPM-pipeline developpers -function bidsCopyRawFolder(opt, deleteZippedNii) - % This function will copy the subject's folders from the "raw" folder to the - % "derivatives" folder, and will copy the dataset description and task json files +function bidsCopyRawFolder(opt, deleteZippedNii, modalitiesToCopy) + % + % This function will copy the subject's folders from the ``raw`` folder to the + % ``derivatives`` folder, and will copy the dataset description and task json files % to the derivatives directory. % Then it will search the derivatives directory for any zipped nii.gz image % and uncompress it to .nii images. % - % INPUT: + % USAGE:: + % + % bidsCopyRawFolder([opt,] ... + % [deleteZippedNii = true,] ... + % [modalitiesToCopy = {'anat', 'func', 'fmap'}]) % - % opt - options structure defined by the getOption function. If no inout is given - % this function will attempt to load a opt.mat file in the same directory - % to try to get some options + % :param opt: + % :type opt: type + % :param deleteZippedNii: + % :type deleteZippedNii: boolean + % :param modalitiesToCopy: + % :type modalitiesToCopy: cell % - % deleteZippedNii - true or false and will delete original zipped files - % after copying and unzipping %% input variables default values - if nargin < 2 % if second argument isn't specified - deleteZippedNii = 1; % delete the original zipped nii.gz + + if nargin < 3 || isempty(modalitiesToCopy) + % Will only copy those modalities if they exist + modalitiesToCopy = {'anat', 'func', 'fmap'}; + end + + if nargin < 2 || isempty(deleteZippedNii) + % delete the original zipped nii.gz + deleteZippedNii = true; end % if input has no opt, load the opt.mat file - if nargin < 1 + if nargin < 1 || isempty(opt) opt = []; end opt = loadAndCheckOptions(opt); - % Will only copy those modalities if they exist - modalitiesToCopy = {'anat', 'func'}; - %% All tasks in this experiment % raw directory and derivatives directory - rawDir = opt.dataDir; opt = setDerivativesDir(opt); + rawDir = opt.dataDir; derivativesDir = opt.derivativesDir; - % make derivatives folder if it doesnt exist - if ~exist(derivativesDir, 'dir') - mkdir(derivativesDir); - fprintf('derivatives directory created: %s \n', derivativesDir); - else - fprintf('derivatives directory already exists. \n'); - end + createDerivativeDir(derivativesDir); - % copy TSV and JSON file from raw folder if it doesnt exist - copyfile(fullfile(rawDir, '*.json'), derivativesDir); - fprintf(' json files copied to derivatives directory \n'); - - try - copyfile(fullfile(rawDir, '*.tsv'), derivativesDir); - fprintf(' tsv files copied to derivatives directory \n'); - catch - end + copyTsvJson(rawDir, derivativesDir); %% Loop through the groups, subjects, sessions [group, opt, BIDS] = getData(opt, rawDir); @@ -76,64 +72,98 @@ function bidsCopyRawFolder(opt, deleteZippedNii) for iSes = 1:nbSessions - sessionFolder = []; + sessionDir = []; if ~isempty(sessions{iSes}) - sessionFolder = ['ses-' sessions{iSes}]; + sessionDir = ['ses-' sessions{iSes}]; end - mkdir(fullfile(derivativesDir, subDir, sessionFolder)); - - modalities = spm_BIDS(BIDS, 'modalities', ... - 'sub', subID, ... - 'ses', sessions{iSes}, ... - 'task', opt.taskName); + mkdir(fullfile(derivativesDir, subDir, sessionDir)); + modalities = bids.query(BIDS, 'modalities', ... + 'sub', subID, ... + 'ses', sessions{iSes}, ... + 'task', opt.taskName); modalities = intersect(modalities, modalitiesToCopy); for iModality = 1:numel(modalities) - try - status = system( ... - sprintf('cp -R -L %s %s', ... - fullfile(rawDir, ... - subDir, ... - sessionFolder, ... - modalities{iModality}), ... - fullfile(derivativesDir, ... - subDir, ... - sessionFolder, ... - modalities{iModality}))); - - if status > 0 - message = [ ... - 'Copying data with system command failed: ' ... - 'Are you running Windows?\n', ... - 'Will use matlab/octave copyfile command instead.\n', ... - 'Maybe your data set contains symbolic links' ... - '(e.g. if you use datalad or git-annex.']; - error(message); - end - - catch - copyfile(fullfile(rawDir, ... - subDir, ... - sessionFolder, ... - modalities{iModality}), ... - fullfile(derivativesDir, ... - subDir, ... - sessionFolder, ... - modalities{iModality})); - end + mkdir(fullfile(derivativesDir, subDir, sessionDir, modalities{iModality})); + + srcFolder = fullfile(rawDir, ... + subDir, ... + sessionDir, ... + modalities{iModality}); + targetFolder = fullfile(derivativesDir, ... + subDir, ... + sessionDir); + + copyModalityDir(srcFolder, targetFolder); end + fprintf('folder copied: %s \n', subDir); + end + end + + end + + unzipFiles(derivativesDir, deleteZippedNii); - fprintf('folder copied: %s \n', subDir); +end + +function createDerivativeDir(derivativesDir) + % make derivatives folder if it doesnt exist + + if ~exist(derivativesDir, 'dir') + mkdir(derivativesDir); + fprintf('derivatives directory created: %s \n', derivativesDir); + else + fprintf('derivatives directory already exists. \n'); + end + +end + +function copyTsvJson(rawDir, derivativesDir) + % copy TSV and JSON file from raw folder + + copyfile(fullfile(rawDir, '*.json'), derivativesDir); + fprintf(' json files copied to derivatives directory \n'); + try + copyfile(fullfile(rawDir, '*.tsv'), derivativesDir); + fprintf(' tsv files copied to derivatives directory \n'); + catch + end + +end + +function copyModalityDir(srcFolder, targetFolder) + + try + status = system( ... + sprintf('cp -R -L -f %s %s', ... + srcFolder, ... + targetFolder)); + + if status > 0 + message = [ ... + 'Copying data with system command failed: ' ... + 'Are you running Windows?\n', ... + 'Will use matlab/octave copyfile command instead.\n', ... + 'Maybe your data set contains symbolic links' ... + '(e.g. if you use datalad or git-annex.']; + error(message); end + + catch + fprintf(1, 'Using octave/matlab to copy files.'); + copyfile(srcFolder, targetFolder); end +end + +function unzipFiles(derivativesDir, deleteZippedNii) %% search for nifti files in a compressed nii.gz format zippedNiifiles = spm_select('FPListRec', derivativesDir, '^.*.nii.gz$'); @@ -145,9 +175,10 @@ function bidsCopyRawFolder(opt, deleteZippedNii) save_untouch_nii(n, file(1:end - 4)); % Save the functional data as unzipped nii fprintf('unzipped: %s \n', file); - if deleteZippedNii == 1 + if deleteZippedNii delete(file); % delete original zipped file end + end end diff --git a/src/workflows/bidsCreateVDM.m b/src/workflows/bidsCreateVDM.m new file mode 100644 index 00000000..ef196688 --- /dev/null +++ b/src/workflows/bidsCreateVDM.m @@ -0,0 +1,51 @@ +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers + +function bidsCreateVDM(opt) + % bidsCreateVDM(opt) + % + % inspired from spmup spmup_BIDS_preprocess (@ commit + % 198c980d6d7520b1a996f0e56269e2ceab72cc83) + + if nargin < 1 + opt = []; + end + opt = loadAndCheckOptions(opt); + + % load the subjects/Groups information and the task name + [group, opt, BIDS] = getData(opt); + + fprintf(1, ' FIELDMAP WORKFLOW\n'); + + %% Loop through the groups, subjects, and sessions + for iGroup = 1:length(group) + + groupName = group(iGroup).name; + + for iSub = 1:group(iGroup).numSub + + subID = group(iGroup).subNumber{iSub}; + + % TODO Move to getInfo + types = spm_BIDS(BIDS, 'types', 'sub', subID); + + if any(ismember(types, {'phase12', 'phasediff', 'fieldmap', 'epi'})) + + printProcessingSubject(groupName, iSub, subID); + + matlabbatch = setBatchCoregistrationFmap(BIDS, opt, subID); + saveMatlabBatch(matlabbatch, 'coregister_fmap', opt, subID); + spm_jobman('run', matlabbatch); + + matlabbatch = setBatchCreateVDMs(BIDS, opt, subID); + saveMatlabBatch(matlabbatch, 'create_vdm', opt, subID); + spm_jobman('run', matlabbatch); + + % TODO + % delete temporary mean images ?? + + end + + end + + end +end diff --git a/src/workflows/bidsRealignReslice.m b/src/workflows/bidsRealignReslice.m index 3f64669a..06dc8444 100644 --- a/src/workflows/bidsRealignReslice.m +++ b/src/workflows/bidsRealignReslice.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function bidsRealignReslice(opt) % bidsRealignReslice(opt) diff --git a/src/workflows/bidsRealignUnwarp.m b/src/workflows/bidsRealignUnwarp.m index 40fe98cd..b3857c06 100644 --- a/src/workflows/bidsRealignUnwarp.m +++ b/src/workflows/bidsRealignUnwarp.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function bidsRealignUnwarp(opt) % bidsRealignReslice(opt) diff --git a/src/workflows/bidsResliceTpmToFunc.m b/src/workflows/bidsResliceTpmToFunc.m index 91469abd..d5a5671f 100644 --- a/src/workflows/bidsResliceTpmToFunc.m +++ b/src/workflows/bidsResliceTpmToFunc.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 2020 CPP BIDS SPM-pipeline developpers function bidsResliceTpmToFunc(opt) % bidsResliceTpmToFunc(opt) diff --git a/src/workflows/bidsSegmentSkullStrip.m b/src/workflows/bidsSegmentSkullStrip.m index 5a60df9d..4ddbfe69 100644 --- a/src/workflows/bidsSegmentSkullStrip.m +++ b/src/workflows/bidsSegmentSkullStrip.m @@ -1,4 +1,4 @@ -% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers +% (C) Copyright 20120 CPP BIDS SPM-pipeline developpers function bidsSegmentSkullStrip(opt) % diff --git a/src/workflows/bidsSpatialPrepro.m b/src/workflows/bidsSpatialPrepro.m index 2a795945..2a100219 100644 --- a/src/workflows/bidsSpatialPrepro.m +++ b/src/workflows/bidsSpatialPrepro.m @@ -57,7 +57,7 @@ function bidsSpatialPrepro(opt) opt.orderBatches.realign = 2; % dependency from file selector ('Anatomical') - matlabbatch = setBatchCoregistration(matlabbatch, BIDS, subID, opt); + matlabbatch = setBatchCoregistrationFuncToAnat(matlabbatch, BIDS, subID, opt); opt.orderBatches.coregister = 3; matlabbatch = setBatchSaveCoregistrationMatrix(matlabbatch, BIDS, subID, opt); diff --git a/tests/README.md b/tests/README.md index f884994b..28db08aa 100644 --- a/tests/README.md +++ b/tests/README.md @@ -7,4 +7,4 @@ coverage = mocov( ... '-cover', fullfile(pwd, '..', 'subfun'), .... '-cover_xml_file', 'coverage.xml', ... '-cover_html_dir', 'coverage_html') -``` \ No newline at end of file +``` diff --git a/tests/test_bidsCopyRawFolder.m b/tests/test_bidsCopyRawFolder.m index a82bd517..fa559eea 100644 --- a/tests/test_bidsCopyRawFolder.m +++ b/tests/test_bidsCopyRawFolder.m @@ -8,6 +8,8 @@ function test_bidsCopyRawFolderBasic() + % TODO add test to only copy some modalities + % directory with this script becomes the current directory opt.dataDir = fullfile( ... fileparts(mfilename('fullpath')), ... diff --git a/tests/test_checkOptions.m b/tests/test_checkOptions.m index cbfe42b1..232f1684 100644 --- a/tests/test_checkOptions.m +++ b/tests/test_checkOptions.m @@ -94,6 +94,8 @@ function test_checkOptionsErrorVoxDim() expectedOptions.skullstrip.threshold = 0.75; + expectedOptions.ignoreFieldmaps = false; + expectedOptions.taskName = ''; expectedOptions.zeropad = 2; diff --git a/tests/test_loadAndCheckOptions.m b/tests/test_loadAndCheckOptions.m index 355fa9e5..ca8c4673 100644 --- a/tests/test_loadAndCheckOptions.m +++ b/tests/test_loadAndCheckOptions.m @@ -108,6 +108,8 @@ function test_loadAndCheckOptionsFromSeveralFiles() expectedOptions.skullstrip.threshold = 0.75; + expectedOptions.ignoreFieldmaps = false; + expectedOptions.taskName = ''; expectedOptions.zeropad = 2; diff --git a/tests/test_setBatchCoregistration.m b/tests/test_setBatchCoregistrationFuncToAnat.m similarity index 91% rename from tests/test_setBatchCoregistration.m rename to tests/test_setBatchCoregistrationFuncToAnat.m index 8bdf6f4a..138029a1 100644 --- a/tests/test_setBatchCoregistration.m +++ b/tests/test_setBatchCoregistrationFuncToAnat.m @@ -1,4 +1,4 @@ -function test_suite = test_setBatchCoregistration %#ok<*STOUT> +function test_suite = test_setBatchCoregistrationFuncToAnat %#ok<*STOUT> try % assignment of 'localfunctions' is necessary in Matlab >= 2016 test_functions = localfunctions(); %#ok<*NASGU> catch % no problem; early Matlab versions can use initTestSuite fine @@ -6,7 +6,7 @@ initTestSuite; end -function test_setBatchCoregistrationBasic() +function test_setBatchCoregistrationFuncToAnatBasic() % necessarry to deal with SPM module dependencies spm_jobman('initcfg'); @@ -24,7 +24,7 @@ function test_setBatchCoregistrationBasic() opt.orderBatches.realign = 2; matlabbatch = {}; - matlabbatch = setBatchCoregistration(matlabbatch, BIDS, subID, opt); + matlabbatch = setBatchCoregistrationFuncToAnat(matlabbatch, BIDS, subID, opt); nbRuns = 4; @@ -44,7 +44,7 @@ function test_setBatchCoregistrationBasic() end -function test_setBatchCoregistrationNative() +function test_setBatchCoregistrationFuncToAnatNative() % necessarry to deal with SPM module dependencies spm_jobman('initcfg'); @@ -63,7 +63,7 @@ function test_setBatchCoregistrationNative() opt.orderBatches.realign = 2; matlabbatch = {}; - matlabbatch = setBatchCoregistration(matlabbatch, BIDS, subID, opt); + matlabbatch = setBatchCoregistrationFuncToAnat(matlabbatch, BIDS, subID, opt); nbRuns = 4;