diff --git a/lib/mancoreg/mancoregCallbacks.m b/lib/mancoreg/mancoregCallbacks.m index c92167bf..40593bd5 100644 --- a/lib/mancoreg/mancoregCallbacks.m +++ b/lib/mancoreg/mancoregCallbacks.m @@ -64,7 +64,7 @@ function mancoregCallbacks(operation) function moveImage() - global st mancoregvar; + global st mancoregvar angl_pitch = get(mancoregvar.hpitch, 'Value'); angl_roll = get(mancoregvar.hroll, 'Value'); @@ -96,7 +96,7 @@ function moveImage() function toggleOff() - global st mancoregvar; + global st mancoregvar if get(mancoregvar.htoggle_off, 'value') == 0 % Source is to be displayed @@ -114,7 +114,7 @@ function toggleOff() function toggleOn() - global st mancoregvar; + global st mancoregvar if get(mancoregvar.htoggle_on, 'value') == 0 % Source is to be displayed @@ -135,7 +135,7 @@ function toggleOn() function resetTransformationMatrix() - global st mancoregvar; + global st mancoregvar set(mancoregvar.hpitch, 'Value', 0); set(mancoregvar.hroll, 'Value', 0); @@ -165,7 +165,7 @@ function resetTransformationMatrix() function applyTransformationMatrix() - global st mancoregvar; + global st mancoregvar angl_pitch = get(mancoregvar.hpitch, 'Value'); angl_roll = get(mancoregvar.hroll, 'Value'); @@ -218,7 +218,7 @@ function applyTransformationMatrix() function plotMat - global mancoregvar; + global mancoregvar angl_pitch = get(mancoregvar.hpitch, 'Value'); angl_roll = get(mancoregvar.hroll, 'Value'); diff --git a/src/batches/setBatchSTC.m b/src/batches/setBatchSTC.m index 462493a0..d71a5d55 100644 --- a/src/batches/setBatchSTC.m +++ b/src/batches/setBatchSTC.m @@ -1,10 +1,10 @@ -function matlabbatch = setBatchSTC(matlabbatch, BIDS, opt, subLabel) +function matlabbatch = setBatchSTC(varargin) % % Creates batch for slice timing correction % % USAGE:: % - % matlabbatch = setBatchSTC(matlabbatch, BIDS, opt, subID) + % matlabbatch = setBatchSTC(matlabbatch, BIDS, opt, subLabel) % % :param BIDS: BIDS layout returned by ``getData``. % :type BIDS: structure @@ -30,6 +30,24 @@ % % (C) Copyright 2019 CPP_SPM developers + p = inputParser; + + addRequired(p, 'matlabbatch', @iscell); + addRequired(p, 'BIDS', @isstruct); + addRequired(p, 'opt', @isstruct); + addRequired(p, 'subLabel', @ischar); + + parse(p, varargin{:}); + + matlabbatch = p.Results.matlabbatch; + BIDS = p.Results.BIDS; + opt = p.Results.opt; + subLabel = p.Results.subLabel; + + if opt.stc.skip + return + end + % get slice order sliceOrder = getSliceOrder(opt, 1); if isempty(sliceOrder) @@ -55,10 +73,10 @@ maxSliceTime = max(sliceOrder); minSliceTime = min(sliceOrder); - if isempty(opt.STC_referenceSlice) + if isempty(opt.stc.referenceSlice) referenceSlice = (maxSliceTime - minSliceTime) / 2; else - referenceSlice = opt.STC_referenceSlice; + referenceSlice = opt.stc.referenceSlice; end if TA >= TR || referenceSlice > TA || any(sliceOrder > TA) @@ -80,11 +98,11 @@ error(errorStruct); end - matlabbatch{end + 1}.spm.temporal.st.nslices = nbSlices; - matlabbatch{end}.spm.temporal.st.tr = TR; - matlabbatch{end}.spm.temporal.st.ta = TA; - matlabbatch{end}.spm.temporal.st.so = sliceOrder * 1000; - matlabbatch{end}.spm.temporal.st.refslice = referenceSlice * 1000; + temporal.st.nslices = nbSlices; + temporal.st.tr = TR; + temporal.st.ta = TA; + temporal.st.so = sliceOrder * 1000; + temporal.st.refslice = referenceSlice * 1000; [sessions, nbSessions] = getInfo(BIDS, subLabel, opt, 'Sessions'); @@ -106,7 +124,7 @@ file = validationInputFile(subFuncDataDir, fileName); % add the file to the list - matlabbatch{end}.spm.temporal.st.scans{runCounter} = {file}; + temporal.st.scans{runCounter} = {file}; runCounter = runCounter + 1; @@ -116,6 +134,8 @@ end + matlabbatch{end + 1}.spm.temporal = temporal; + % The following lines are commented out because those parameters % can be set in the spm_my_defaults.m % matlabbatch{1}.spm.temporal.st.prefix = spm_get_defaults('slicetiming.prefix'); diff --git a/src/batches/setBatchSubjectLevelGLMSpec.m b/src/batches/setBatchSubjectLevelGLMSpec.m index 1dd3d941..fbfd0452 100644 --- a/src/batches/setBatchSubjectLevelGLMSpec.m +++ b/src/batches/setBatchSubjectLevelGLMSpec.m @@ -57,10 +57,10 @@ % If no reference slice is given for STC, then STC took the mid-volume % time point to do the correction. % When no STC was done, this is usually a good way to do it too. - if isempty(opt.STC_referenceSlice) + if isempty(opt.stc.referenceSlice) refBin = floor(nbTimeBins / 2); else - refBin = opt.STC_referenceSlice / opt.metadata.RepetitionTime; + refBin = opt.stc.referenceSlice / opt.metadata.RepetitionTime; end matlabbatch{end}.spm.stats.fmri_spec.timing.fmri_t0 = refBin; diff --git a/src/defaults/checkOptions.m b/src/defaults/checkOptions.m index 5449cb61..ecd57052 100644 --- a/src/defaults/checkOptions.m +++ b/src/defaults/checkOptions.m @@ -50,9 +50,10 @@ % will be included in the mask. % - ``opt.funcVoxelDims = []`` - Voxel dimensions to use for resampling of functional data % at normalization. - % - ``opt.STC_referenceSlice = []`` - reference slice for the slice timing correction. + % - ``opt.stc.skip = false`` - boolean flag to skip slice time correction or not. + % - ``opt.stc.referenceSlice = []`` - reference slice for the slice timing correction. % If left emtpy the mid-volume acquisition time point will be selected at run time. - % - ``opt.sliceOrder = []`` - To be used if SPM can't extract slice info. NOT RECOMMENDED, + % - ``opt.stc.sliceOrder = []`` - To be used if SPM can't extract slice info. NOT RECOMMENDED, % if you know the order in which slices were acquired, you should be able to recompute % slice timing and add it to the json files in your BIDS data set. % - ``opt.glm.roibased.do`` @@ -112,8 +113,9 @@ %% Options for slice time correction % all in seconds - fieldsToSet.STC_referenceSlice = []; - fieldsToSet.sliceOrder = []; + fieldsToSet.stc.referenceSlice = []; + fieldsToSet.stc.sliceOrder = []; + fieldsToSet.stc.skip = false; %% Options for realign fieldsToSet.realign.useUnwarp = true; @@ -173,13 +175,13 @@ function checkFields(opt) end - if ~isempty (opt.STC_referenceSlice) && length(opt.STC_referenceSlice) > 1 + if ~isempty (opt.stc.referenceSlice) && length(opt.stc.referenceSlice) > 1 errorStruct.identifier = 'checkOptions:refSliceNotScalar'; errorStruct.message = sprintf( ... - ['options.STC_referenceSlice should be a scalar.' ... + ['options.stc.referenceSlice should be a scalar.' ... '\nCurrent value is: %d'], ... - opt.STC_referenceSlice); + opt.stc.referenceSlice); error(errorStruct); end diff --git a/src/getPrefix.m b/src/getPrefix.m index c6d98dc1..724ea992 100644 --- a/src/getPrefix.m +++ b/src/getPrefix.m @@ -109,9 +109,10 @@ function prefix = prefixForSTC(prefix, opt) % Check the slice timing information is not in the metadata and not added % manually in the opt variable. - if (isfield(opt.metadata, 'SliceTiming') && ... - ~isempty(opt.metadata.SliceTiming)) || ... - ~isempty(opt.sliceOrder) + if ~opt.stc.skip && ... + ((isfield(opt.metadata, 'SliceTiming') && ... + ~isempty(opt.metadata.SliceTiming)) || ... + ~isempty(opt.stc.sliceOrder)) prefix = [spm_get_defaults('slicetiming.prefix') prefix]; end end diff --git a/src/getSliceOrder.m b/src/getSliceOrder.m index 1d2e1037..d4aa73d1 100644 --- a/src/getSliceOrder.m +++ b/src/getSliceOrder.m @@ -41,8 +41,8 @@ % If slice timing information is not in the metadata, you have the option % to add the slice order manually in the "opt" in the "getOptions" % function - if ~isempty(opt.sliceOrder) - sliceOrder = opt.sliceOrder; + if ~isempty(opt.stc.sliceOrder) + sliceOrder = opt.stc.sliceOrder; msg{end + 1} = ' SLICE TIMING INFORMATION EXTRACTED FROM OPTIONS.\n\n'; diff --git a/tests/test_checkOptions.m b/tests/test_checkOptions.m index 383c71f0..76ac996e 100644 --- a/tests/test_checkOptions.m +++ b/tests/test_checkOptions.m @@ -55,7 +55,7 @@ function test_checkOptionsErrorGroup() function test_checkOptionsErrorRefSlice() - opt.STC_referenceSlice = [1:10]; + opt.stc.referenceSlice = [1:10]; opt.taskName = 'testTask'; assertExceptionThrown( ... diff --git a/tests/test_setBatchSTC.m b/tests/test_setBatchSTC.m index 85817da4..368377c0 100644 --- a/tests/test_setBatchSTC.m +++ b/tests/test_setBatchSTC.m @@ -8,6 +8,22 @@ initTestSuite; end +function test_setBatchSTCSkip() + + subLabel = '02'; + + opt = setOptions('vislocalizer', subLabel); + + [BIDS, opt] = getData(opt); + + opt.stc.skip = true; + + matlabbatch = {}; + matlabbatch = setBatchSTC(matlabbatch, BIDS, opt, subLabel); + assertEqual(matlabbatch, {}); + +end + function test_setBatchSTCEmpty() subLabel = '02'; @@ -16,11 +32,11 @@ function test_setBatchSTCEmpty() [BIDS, opt] = getData(opt); - matlabbatch = []; + matlabbatch = {}; matlabbatch = setBatchSTC(matlabbatch, BIDS, opt, subLabel); % no slice timing info for this run so nothing should be returned. - assertEqual(matlabbatch, []); + assertEqual(matlabbatch, {}); end @@ -31,19 +47,19 @@ function test_setBatchSTCForce() opt = setOptions('vislocalizer', subLabel); % we give it some slice timing value to force slice timing to happen - opt.sliceOrder = linspace(0, 1.6, 10); - opt.sliceOrder(end - 1:end) = []; - opt.STC_referenceSlice = 1.6 / 2; + opt.stc.sliceOrder = linspace(0, 1.6, 10); + opt.stc.sliceOrder(end - 1:end) = []; + opt.stc.referenceSlice = 1.6 / 2; opt = checkOptions(opt); [BIDS, opt] = getData(opt); - matlabbatch = []; + matlabbatch = {}; matlabbatch = setBatchSTC(matlabbatch, BIDS, opt, subLabel); TR = 1.55; - expectedBatch = returnExpectedBatch(opt.sliceOrder, opt.STC_referenceSlice, TR); + expectedBatch = returnExpectedBatch(opt.stc.sliceOrder, opt.stc.referenceSlice, TR); runCounter = 1; for iSes = 1:2 @@ -69,7 +85,7 @@ function test_setBatchSTCBasic() [BIDS, opt] = getData(opt); - matlabbatch = []; + matlabbatch = {}; matlabbatch = setBatchSTC(matlabbatch, BIDS, opt, subLabel); TR = 1.5; @@ -77,9 +93,9 @@ function test_setBatchSTCBasic() 0.5475, 0, 0.3825, 0.055, 0.4375, 0.11, 0.4925, 0.22, 0.6025, ... 0.275, 0.6575, ... 0.3275, 0.71, 0.165], 1, 3)'; - STC_referenceSlice = 0.355; + referenceSlice = 0.355; - expectedBatch = returnExpectedBatch(sliceOrder, STC_referenceSlice, TR); + expectedBatch = returnExpectedBatch(sliceOrder, referenceSlice, TR); runCounter = 1; for iSes = 1:2 @@ -106,14 +122,13 @@ function test_setBatchSTCErrorInvalidInputTime() opt = setOptions('vislocalizer', subLabel); - opt.sliceOrder = linspace(0, 1.6, 10); - opt.sliceOrder(end) = []; - opt.STC_referenceSlice = 2; % impossible reference value + opt.stc.sliceOrder = linspace(0, 1.6, 10); + opt.stc.sliceOrder(end) = []; + opt.stc.referenceSlice = 2; % impossible reference value [BIDS, opt] = getData(opt); - matlabbatch = []; - + matlabbatch = {}; assertExceptionThrown( ... @()setBatchSTC(matlabbatch, BIDS, opt, subLabel), ... 'setBatchSTC:invalidInputTime'); @@ -126,10 +141,12 @@ function test_setBatchSTCErrorInvalidInputTime() TA = TR - (TR / nbSlices); TA = ceil(TA * 1000) / 1000; - expectedBatch{1}.spm.temporal.st.nslices = nbSlices; - expectedBatch{1}.spm.temporal.st.tr = TR; - expectedBatch{1}.spm.temporal.st.ta = TA; - expectedBatch{1}.spm.temporal.st.so = sliceOrder * 1000; - expectedBatch{1}.spm.temporal.st.refslice = referenceSlice * 1000; + temporal.st.nslices = nbSlices; + temporal.st.tr = TR; + temporal.st.ta = TA; + temporal.st.so = sliceOrder * 1000; + temporal.st.refslice = referenceSlice * 1000; + + expectedBatch{1}.spm.temporal = temporal; end diff --git a/tests/test_unit_getPrefix.m b/tests/test_unit_getPrefix.m index c8bd5e0a..bb9ba594 100644 --- a/tests/test_unit_getPrefix.m +++ b/tests/test_unit_getPrefix.m @@ -8,13 +8,30 @@ initTestSuite; end +function test_getPrefixSkipSTC() + + step = 'realign'; + + opt.metadata.SliceTiming = 1:0.2:1.8; + opt.stc.sliceOrder = 1:10; + opt.stc.skip = true; + opt = checkOptions(opt); + + prefix = getPrefix(step, opt); + + expectedPrefixOutput = ''; + + assertEqual(prefix, expectedPrefixOutput); + +end + function test_getPrefixSTC() step = 'realign'; - funcFWHM = 6; opt.metadata.SliceTiming = 1:0.2:1.8; - opt.sliceOrder = 1:10; + opt.stc.sliceOrder = 1:10; + opt = checkOptions(opt); [prefix, motionRegressorPrefix] = getPrefix(step, opt); @@ -31,7 +48,7 @@ function test_getPrefixNoSTC() step = 'realign'; opt.metadata = []; - opt.sliceOrder = []; + opt = checkOptions(opt); prefix = getPrefix(step, opt); @@ -46,9 +63,9 @@ function test_getPrefixMean() step = 'mean'; opt.metadata = []; - opt.sliceOrder = []; opt.realign.useUnwarp = true; opt.space = 'MNI'; + opt = checkOptions(opt); prefix = getPrefix(step, opt); @@ -60,9 +77,10 @@ function test_getPrefixMean() step = 'mean'; opt.metadata.SliceTiming = 1:0.2:1.8; - opt.sliceOrder = 1:10; + opt.stc.sliceOrder = 1:10; opt.realign.useUnwarp = false; opt.space = 'MNI'; + opt = checkOptions(opt); prefix = getPrefix(step, opt); @@ -76,9 +94,9 @@ function test_getPrefixNormalise() step = 'normalise'; opt.metadata = []; - opt.sliceOrder = []; opt.realign.useUnwarp = true; opt.space = 'MNI'; + opt = checkOptions(opt); prefix = getPrefix(step, opt); @@ -90,9 +108,9 @@ function test_getPrefixNormalise() step = 'normalise'; opt.metadata = []; - opt.sliceOrder = []; opt.realign.useUnwarp = false; opt.space = 'MNI'; + opt = checkOptions(opt); prefix = getPrefix(step, opt); @@ -106,9 +124,9 @@ function test_getPrefixFuncQA() step = 'funcQA'; opt.metadata = []; - opt.sliceOrder = []; opt.realign.useUnwarp = true; opt.space = 'MNI'; + opt = checkOptions(opt); prefix = getPrefix(step, opt); @@ -120,9 +138,9 @@ function test_getPrefixFuncQA() step = 'funcQA'; opt.metadata = []; - opt.sliceOrder = []; opt.realign.useUnwarp = false; opt.space = 'MNI'; + opt = checkOptions(opt); prefix = getPrefix(step, opt); @@ -136,9 +154,9 @@ function test_getPrefixSmooth() step = 'smooth'; opt.metadata = []; - opt.sliceOrder = []; opt.realign.useUnwarp = true; opt.space = 'MNI'; + opt = checkOptions(opt); prefix = getPrefix(step, opt); @@ -151,6 +169,7 @@ function test_getPrefixSmooth() %% native space opt.realign.useUnwarp = true; opt.space = 'individual'; + opt = checkOptions(opt); prefix = getPrefix(step, opt); @@ -161,6 +180,7 @@ function test_getPrefixSmooth() %% native space no unwarp opt.realign.useUnwarp = false; opt.space = 'individual'; + opt = checkOptions(opt); prefix = getPrefix(step, opt); @@ -171,6 +191,7 @@ function test_getPrefixSmooth() %% MNI space no unwarp opt.realign.useUnwarp = false; opt.space = 'MNI'; + opt = checkOptions(opt); prefix = getPrefix(step, opt); @@ -185,9 +206,9 @@ function test_getPrefixFFX() step = 'FFX'; funcFWHM = 6; opt.metadata = []; - opt.sliceOrder = []; opt.realign.useUnwarp = true; opt.space = 'MNI'; + opt = checkOptions(opt); [prefix, motionRegressorPrefix] = getPrefix(step, opt, funcFWHM); @@ -204,6 +225,7 @@ function test_getPrefixFFX() %% native space opt.realign.useUnwarp = true; opt.space = 'individual'; + opt = checkOptions(opt); [prefix, motionRegressorPrefix] = getPrefix(step, opt, funcFWHM); @@ -220,7 +242,8 @@ function test_getPrefixFFX() opt.realign.useUnwarp = false; opt.space = 'individual'; opt.metadata.SliceTiming = 1:0.2:1.8; - opt.sliceOrder = 1:10; + opt.stc.sliceOrder = 1:10; + opt = checkOptions(opt); [prefix, motionRegressorPrefix] = getPrefix(step, opt, funcFWHM); @@ -238,14 +261,15 @@ function test_getPrefixFFX() opt.realign.useUnwarp = false; opt.space = 'MNI'; opt.metadata = []; - opt.sliceOrder = []; + opt = checkOptions(opt); [prefix] = getPrefix(step, opt, funcFWHM); expectedPrefixOutput = sprintf('%s%i%s%s', ... spm_get_defaults('smooth.prefix'), ... funcFWHM, ... - spm_get_defaults('normalise.write.prefix')); + spm_get_defaults('normalise.write.prefix'), ... + spm_get_defaults('slicetiming.prefix')); expectedMotionRegressorPrefix = spm_get_defaults('slicetiming.prefix'); assertEqual(prefix, expectedPrefixOutput); @@ -257,7 +281,7 @@ function test_getPrefixError() step = 'error'; funcFWHM = 6; opt.metadata = []; - opt.sliceOrder = []; + opt = checkOptions(opt); assertExceptionThrown( ... @()getPrefix(step, opt, funcFWHM), ... diff --git a/tests/test_unit_getSliceOrder.m b/tests/test_unit_getSliceOrder.m index 543c141e..6a43a199 100644 --- a/tests/test_unit_getSliceOrder.m +++ b/tests/test_unit_getSliceOrder.m @@ -51,11 +51,11 @@ function test_getSliceOrderEmpty() function test_getSliceOrderFromOptions() opt = setOptions('vislocalizer'); - opt.STC_referenceSlice = 1000; - opt.sliceOrder = 0:250:2000; + opt.stc.referenceSlice = 1000; + opt.stc.sliceOrder = 0:250:2000; [~, opt] = getData(opt); BIDS_sliceOrder = getSliceOrder(opt, 0); - assert(isequal(BIDS_sliceOrder, opt.sliceOrder)); + assert(isequal(BIDS_sliceOrder, opt.stc.sliceOrder)); end diff --git a/tests/utils/defaultOptions.m b/tests/utils/defaultOptions.m index 42cc31c1..fe71b2cd 100644 --- a/tests/utils/defaultOptions.m +++ b/tests/utils/defaultOptions.m @@ -2,8 +2,9 @@ % % (C) Copyright 2021 CPP_SPM developers - expectedOptions.sliceOrder = []; - expectedOptions.STC_referenceSlice = []; + expectedOptions.stc.sliceOrder = []; + expectedOptions.stc.referenceSlice = []; + expectedOptions.stc.skip = false; expectedOptions.dataDir = ''; expectedOptions.derivativesDir = '';