Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/run_system_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ jobs:

- name: Update octave path
run: |
octave $OCTFLAGS --eval "addpath(genpath(fullfile(pwd, 'lib'))); savepath();"
octave $OCTFLAGS --eval "addpath(genpath(fullfile(pwd, 'src'))); savepath();"
octave $OCTFLAGS --eval "initCppSpm; savepath();"

- name: Prepare data
run: |
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/run_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ jobs:

- name: Update octave path
run: |
octave $OCTFLAGS --eval "addpath(genpath(fullfile(pwd, 'lib'))); savepath();"
octave $OCTFLAGS --eval "addpath(genpath(fullfile(pwd, 'src'))); savepath();"
octave $OCTFLAGS --eval "initCppSpm; savepath();"
octave $OCTFLAGS --eval "addpath(fullfile(pwd, 'tests', 'utils')); savepath();"

- name: Prepare data
run: |
Expand Down
7 changes: 1 addition & 6 deletions demos/openneuro/ds000001_run.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,7 @@
FWHM = 6;
conFWHM = 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(genpath(fullfile(WD, '..', '..', 'src')));
addpath(genpath(fullfile(WD, '..', '..', 'lib')));
initCppSpm();

%% Set options
opt = ds000001_getOption();
Expand Down
7 changes: 1 addition & 6 deletions demos/openneuro/ds000114_run.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,7 @@
FWHM = 6;
conFWHM = 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(genpath(fullfile(WD, '..', '..', 'src')));
addpath(genpath(fullfile(WD, '..', '..', 'lib')));
initCppSpm();

%% Set options
opt = ds000114_getOption();
Expand Down
7 changes: 1 addition & 6 deletions demos/openneuro/ds001168_run.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,7 @@
% 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(genpath(fullfile(WD, '..', '..', 'src')));
addpath(genpath(fullfile(WD, '..', '..', 'lib')));
initCppSpm();

%% Set options
opt = ds001168_getOption();
Expand Down
4 changes: 1 addition & 3 deletions demos/spm_face_rep/face_rep_run.m
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@
% directory with this script becomes the current directory
WD = fileparts(mfilename('fullpath'));

% we add all the subfunctions that are in the sub directories
addpath(genpath(fullfile(WD, '..', '..', 'src')));
addpath(genpath(fullfile(WD, '..', '..', 'lib')));
initCppSpm();

%% Set options
opt = FaceRep_getOption();
Expand Down
7 changes: 6 additions & 1 deletion initCppSpm.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ function initCppSpm()

% we add all the subfunctions that are in the sub directories
addpath(genpath(fullfile(WD, 'src')));
addpath(genpath(fullfile(WD, 'lib')));
addpath(genpath(fullfile(WD, 'lib', 'mancoreg')));
addpath(genpath(fullfile(WD, 'lib', 'NiftiTools')));
addpath(genpath(fullfile(WD, 'lib', 'spmup')));
addpath(genpath(fullfile(WD, 'lib', 'utils')));

addpath(fullfile(WD, 'lib', 'bids-matlab'));

end
44 changes: 19 additions & 25 deletions src/QA/anatomicalQA.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,43 +23,37 @@ function anatomicalQA(opt)
end
opt = loadAndCheckOptions(opt);

[group, opt, BIDS] = getData(opt);
[BIDS, opt] = getData(opt);

fprintf(1, ' ANATOMICAL: QUALITY CONTROL\n\n');

%% Loop through the groups, subjects, and sessions
for iGroup = 1:length(group)
parfor iSub = 1:numel(opt.subjects)

groupName = group(iGroup).name;
subID = opt.subjects{iSub};

parfor iSub = 1:group(iGroup).numSub
printProcessingSubject(iSub, subID);

subID = group(iGroup).subNumber{iSub};
[anatImage, anatDataDir] = getAnatFilename(BIDS, subID, opt);

printProcessingSubject(groupName, iSub, subID);
% get grey and white matter tissue probability maps
TPMs = validationInputFile(anatDataDir, anatImage, 'c[12]');

[anatImage, anatDataDir] = getAnatFilename(BIDS, subID, opt);
% sanity check that all images are in the same space.
anatImage = fullfile(anatDataDir, anatImage);
volumesToCheck = {anatImage; TPMs(1, :); TPMs(2, :)};
spm_check_orientations(spm_vol(char(volumesToCheck)));

% get grey and white matter tissue probability maps
TPMs = validationInputFile(anatDataDir, anatImage, 'c[12]');
% Basic QA for anatomical data is to get SNR, CNR, FBER and Entropy
% This is useful to check coregistration worked fine
anatQA = spmup_anatQA(anatImage, TPMs(1, :), TPMs(2, :)); %#ok<*NASGU>

% sanity check that all images are in the same space.
anatImage = fullfile(anatDataDir, anatImage);
volumesToCheck = {anatImage; TPMs(1, :); TPMs(2, :)};
spm_check_orientations(spm_vol(char(volumesToCheck)));
anatQA.avgDistToSurf = spmup_comp_dist2surf(anatImage);

% Basic QA for anatomical data is to get SNR, CNR, FBER and Entropy
% This is useful to check coregistration worked fine
anatQA = spmup_anatQA(anatImage, TPMs(1, :), TPMs(2, :)); %#ok<*NASGU>
spm_jsonwrite( ...
strrep(anatImage, '.nii', '_qa.json'), ...
anatQA, ...
struct('indent', ' '));

anatQA.avgDistToSurf = spmup_comp_dist2surf(anatImage);

spm_jsonwrite( ...
strrep(anatImage, '.nii', '_qa.json'), ...
anatQA, ...
struct('indent', ' '));

end
end

end
145 changes: 69 additions & 76 deletions src/QA/functionalQA.m
Original file line number Diff line number Diff line change
Expand Up @@ -35,106 +35,99 @@ function functionalQA(opt)
end
opt = loadAndCheckOptions(opt);

[group, opt, BIDS] = getData(opt);
[BIDS, opt] = getData(opt);

fprintf(1, ' FUNCTIONAL: QUALITY CONTROL\n\n');

%% Loop through the groups, subjects, and sessions
for iGroup = 1:length(group)
for iSub = 1:numel(opt.subjects)

groupName = group(iGroup).name;
subID = opt.subjects{iSub};

for iSub = 1:group(iGroup).numSub
printProcessingSubject(iSub, subID);

subID = group(iGroup).subNumber{iSub};
% get grey and white matter and csf tissue probability maps
[anatImage, anatDataDir] = getAnatFilename(BIDS, subID, opt);
TPMs = validationInputFile(anatDataDir, anatImage, 'rc[123]');

printProcessingSubject(groupName, iSub, subID);
% load metrics from anat QA
anatQA = spm_jsonread( ...
fullfile( ...
anatDataDir, ...
strrep(anatImage, '.nii', '_qa.json')));

% get grey and white matter and csf tissue probability maps
[anatImage, anatDataDir] = getAnatFilename(BIDS, subID, opt);
TPMs = validationInputFile(anatDataDir, anatImage, 'rc[123]');
[sessions, nbSessions] = getInfo(BIDS, subID, opt, 'Sessions');

% load metrics from anat QA
anatQA = spm_jsonread( ...
fullfile( ...
anatDataDir, ...
strrep(anatImage, '.nii', '_qa.json')));
for iSes = 1:nbSessions

[sessions, nbSessions] = getInfo(BIDS, subID, opt, 'Sessions');
% get all runs for that subject across all sessions
[runs, nbRuns] = getInfo(BIDS, subID, opt, 'Runs', sessions{iSes});

for iSes = 1:nbSessions
for iRun = 1:nbRuns

% get all runs for that subject across all sessions
[runs, nbRuns] = getInfo(BIDS, subID, opt, 'Runs', sessions{iSes});
% get the filename for this bold run for this task
[fileName, subFuncDataDir] = getBoldFilename( ...
BIDS, ...
subID, ...
sessions{iSes}, ...
runs{iRun}, ...
opt);

for iRun = 1:nbRuns
prefix = getPrefix('funcQA', opt);
funcImage = validationInputFile(subFuncDataDir, fileName, prefix);

% get the filename for this bold run for this task
[fileName, subFuncDataDir] = getBoldFilename( ...
BIDS, ...
subID, ...
sessions{iSes}, ...
runs{iRun}, ...
opt);
% sanity check that all images are in the same space.
volumesToCheck = {funcImage; TPMs(1, :); TPMs(2, :); TPMs(3, :)};
spm_check_orientations(spm_vol(char(volumesToCheck)));

prefix = getPrefix('funcQA', opt);
funcImage = validationInputFile(subFuncDataDir, fileName, prefix);
fMRIQA = computeFuncQAMetrics(funcImage, TPMs, anatQA.avgDistToSurf, opt);

% sanity check that all images are in the same space.
volumesToCheck = {funcImage; TPMs(1, :); TPMs(2, :); TPMs(3, :)};
spm_check_orientations(spm_vol(char(volumesToCheck)));
% TODO
% find an ouput format that is leaner than a 3 Gb json file!!!
% spm_jsonwrite( ...
% fullfile( ...
% subFuncDataDir, ...
% strrep(fileName, '.nii', '_qa.json')), ...
% fMRIQA, ...
% struct('indent', ' '));
% save( ...
% fullfile( ...
% subFuncDataDir, ...
% strrep(fileName, '.nii', '_qa.mat')), ...
% 'fMRIQA');

fMRIQA = computeFuncQAMetrics(funcImage, TPMs, anatQA.avgDistToSurf, opt);
outputFiles = spmup_first_level_qa( ...
funcImage, ...
'Voltera', 'on', ...
'Radius', anatQA.avgDistToSurf);

% TODO
% find an ouput format that is leaner than a 3 Gb json file!!!
% spm_jsonwrite( ...
% fullfile( ...
% subFuncDataDir, ...
% strrep(fileName, '.nii', '_qa.json')), ...
% fMRIQA, ...
% struct('indent', ' '));
% save( ...
% fullfile( ...
% subFuncDataDir, ...
% strrep(fileName, '.nii', '_qa.mat')), ...
% 'fMRIQA');
movefile( ...
fullfile(subFuncDataDir, 'spmup_QC.ps'), ...
fullfile(subFuncDataDir, strrep(fileName, '.nii', '_qa.ps')));

outputFiles = spmup_first_level_qa( ...
funcImage, ...
'Voltera', 'on', ...
'Radius', anatQA.avgDistToSurf);
confounds = load(outputFiles.design);

movefile( ...
fullfile(subFuncDataDir, 'spmup_QC.ps'), ...
fullfile(subFuncDataDir, strrep(fileName, '.nii', '_qa.ps')));
spm_save( ...
fullfile( ...
subFuncDataDir, ...
strrep(fileName, ...
'_bold.nii', ...
'_desc-confounds_regressors.tsv')), ...
confounds);

confounds = load(outputFiles.design);
delete(outputFiles.design);

spm_save( ...
fullfile( ...
subFuncDataDir, ...
strrep(fileName, ...
'_bold.nii', ...
'_desc-confounds_regressors.tsv')), ...
confounds);
createDataDictionary(subFuncDataDir, fileName, size(confounds, 2));

delete(outputFiles.design);

createDataDictionary(subFuncDataDir, fileName, size(confounds, 2));

% create carpet plot

% horrible hack to prevent the "abrupt" way spmup_volumecorr crashes
% if nansum is not there
if exist('nansum', 'file') == 2
spmup_timeseriesplot(funcImage, TPMs(1, :), TPMs(2, :), TPMs(3, :), ...
'motion', 'on', ...
'nuisances', 'on', ...
'correlation', 'on', ...
'makefig', 'on');
end
% create carpet plot

% horrible hack to prevent the "abrupt" way spmup_volumecorr crashes
% if nansum is not there
if exist('nansum', 'file') == 2
spmup_timeseriesplot(funcImage, TPMs(1, :), TPMs(2, :), TPMs(3, :), ...
'motion', 'on', ...
'nuisances', 'on', ...
'correlation', 'on', ...
'makefig', 'on');
end

end
Expand Down
20 changes: 10 additions & 10 deletions src/batches/setBatchCoregistrationFmap.m
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
% (C) Copyright 2020 CPP BIDS SPM-pipeline developers

function matlabbatch = setBatchCoregistrationFmap(matlabbatch, BIDS, opt, subID)
function matlabbatch = setBatchCoregistrationFmap(matlabbatch, BIDS, opt, subLabel)
%
% Set the batch for the coregistration of field maps
%
% USAGE::
%
% matlabbatch = setBatchCoregistrationFmap(matlabbatch, BIDS, opt, subID)
% matlabbatch = setBatchCoregistrationFmap(matlabbatch, BIDS, opt, subLabel)
%
% :param BIDS: BIDS layout returned by ``getData``.
% :type BIDS: structure
% :param opt: structure or json filename containing the options. See
% ``checkOptions()`` and ``loadAndCheckOptions()``.
% :type opt: structure
% :param subID: subject ID
% :type subID: string
% :param subLabel:
% :type subLabel: string
%
% :returns: - :matlabbatch: (structure) The matlabbatch ready to run the spm job
%
Expand All @@ -26,31 +26,31 @@

% Use a rough mean of the 1rst run to improve SNR for coregistration
% created by spmup
[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);
[sessions, nbSessions] = getInfo(BIDS, subLabel, opt, 'Sessions');
runs = getInfo(BIDS, subLabel, opt, 'Runs', sessions{1});
[fileName, subFuncDataDir] = getBoldFilename(BIDS, subLabel, sessions{1}, runs{1}, opt);
refImage = validationInputFile(subFuncDataDir, fileName, 'mean_');

for iSes = 1:nbSessions

runs = bids.query(BIDS, 'runs', ...
'modality', 'fmap', ...
'sub', subID, ...
'sub', subLabel, ...
'ses', sessions{iSes});

for iRun = 1:numel(runs)

metadata = bids.query(BIDS, 'metadata', ...
'modality', 'fmap', ...
'sub', subID, ...
'sub', subLabel, ...
'ses', sessions{iSes}, ...
'run', runs{iRun});

if strfind(metadata.IntendedFor, opt.taskName)

fmapFiles = bids.query(BIDS, 'data', ...
'modality', 'fmap', ...
'sub', subID, ...
'sub', subLabel, ...
'ses', sessions{iSes}, ...
'run', runs{iRun});

Expand Down
Loading