From 5884be462a6a168035b259bacb12ecad12a53355 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Mon, 29 Jul 2024 18:08:57 +0200 Subject: [PATCH] fix --- src/bids_model/getDummyContrastsList.m | 2 +- .../subject_level/test_specifyContrasts.m | 157 ++++++++++-------- .../test_specifyDummyContrasts.m | 2 +- .../test_specifyDummyContrasts_Session.m | 5 +- 4 files changed, 92 insertions(+), 74 deletions(-) diff --git a/src/bids_model/getDummyContrastsList.m b/src/bids_model/getDummyContrastsList.m index 1821590a6..460c38e6c 100644 --- a/src/bids_model/getDummyContrastsList.m +++ b/src/bids_model/getDummyContrastsList.m @@ -43,7 +43,7 @@ case 'run' - dummyContrastsList = node.Model.X; + dummyContrastsList = node.Model.HRF.Variables; case {'session', 'subject'} diff --git a/tests/tests_stats/subject_level/test_specifyContrasts.m b/tests/tests_stats/subject_level/test_specifyContrasts.m index e6b2e4be8..f06726d40 100644 --- a/tests/tests_stats/subject_level/test_specifyContrasts.m +++ b/tests/tests_stats/subject_level/test_specifyContrasts.m @@ -9,6 +9,7 @@ end function test_specifyContrasts_bug_854() + % no error when no contrast to build % GIVEN subLabel = '01'; @@ -29,8 +30,8 @@ function test_specifyContrasts_bug_854() spmMatFile = cellstr(fullfile(ffxDir, 'SPM.mat')); load(spmMatFile{1}, 'SPM'); - % WHEN - contrasts = specifyContrasts(opt.model.bm, SPM); + assertWarning(@()specifyContrasts(opt.model.bm, SPM), ... + 'specifyContrasts:noContrast'); end @@ -62,6 +63,80 @@ function test_specifyContrasts_bug_815() end +function test_specifyContrasts_subject_level() + + taskName = 'motion'; + + % GIVEN + DummyContrasts{1} = 'motion'; + DummyContrasts{2} = 'static'; + + Contrasts.Name = 'motion_gt_static'; + Contrasts.ConditionList = {'motion', 'static'}; + Contrasts.Weights = [1, -1]; + Contrasts.Test = 't'; + + model = BidsModel('init', true); + + model.Input.task = taskName; + + model.Nodes{1, 1}.DummyContrasts.Contrasts = DummyContrasts; + model.Nodes{1, 1}.Contrasts{1} = Contrasts; + model.Nodes{1, 1}.GroupBy = {'run', 'subject'}; + model.Nodes{1, 1}.Model.HRF.Variables = {'motion', 'static'}; + + model.Nodes{2, 1} = BidsModel.empty_node('subject'); + model.Nodes{2, 1}.GroupBy = {'subject', 'contrast'}; + model.Nodes{2, 1}.DummyContrasts = struct('Test', 't'); + model.Nodes{2, 1} = rmfield(model.Nodes{2}, 'Contrasts'); + model.Nodes{2, 1}.Model.X = 1; + + SPM.Sess(1).col = [1, 2]; + % skip Sess 2 to make sure contrast naming is based on the Sess number + SPM.Sess(3).col = [3, 4]; + SPM.Sess(4).col = [5, 6]; + + SPM.xX.name = { ... + ' motion*bf(1)' + ' static*bf(1)' + ' motion*bf(1)' + ' static*bf(1)' + ' motion*bf(1)' + ' static*bf(1)' + }; + + SPM.xX.X = ones(1, numel(SPM.xX.name)); + + % WHEN + contrasts = specifyContrasts(model, SPM); + + % THEN + names_contrast = { ... + 'motion_1', [1 0 0 0 0 0] + 'motion_3', [0 0 1 0 0 0] + 'motion_4', [0 0 0 0 1 0] + 'static_1', [0 1 0 0 0 0] + 'static_3', [0 0 0 1 0 0] + 'static_4', [0 0 0 0 0 1] + 'motion_gt_static_1', [1 -1 0 0 0 0] + 'motion_gt_static_3', [0 0 1 -1 0 0] + 'motion_gt_static_4', [0 0 0 0 1 -1] + 'motion', [1 0 1 0 1 0] + 'static', [0 1 0 1 0 1] + 'motion_gt_static', [1 -1 1 -1 1 -1] + }; + + assertEqual(numel(contrasts), size(names_contrast, 1)); + + for i = 1:size(names_contrast, 1) + expected(i).name = names_contrast{i, 1}; + expected(i).C = names_contrast{i, 2}; + expected(i).type = 't'; + assertEqual(contrasts(i), expected(i)); + end + +end + function test_specifyContrasts_subject_level_select_node() taskName = 'motion'; @@ -132,6 +207,7 @@ function test_specifyContrasts_run_level_dummy_contrast_from_X() model.Input.task = taskName; model.Nodes = []; model.Nodes{1}.Model.X = {'motion', 'static'}; + model.Nodes{1}.Model.HRF.Variables = {'motion', 'static'}; model.Nodes{1}.Name = 'run_level'; model.Nodes{1}.Level = 'Run'; model.Nodes{1}.DummyContrasts = struct('Test', 't'); @@ -188,8 +264,12 @@ function test_specifyContrasts_missing_condition_for_dummy_contrasts() model.Input.task = taskName; model.Nodes = []; model.Nodes{1}.Level = 'Run'; + model.Nodes{1}.Name = 'Run'; + model.Nodes{1}.GroupBy = {'run', 'subject'}; model.Nodes{1}.DummyContrasts.Contrasts = DummyContrasts; model.Nodes{1}.DummyContrasts.Test = 't'; + model.Nodes{1}.Model = struct('X', {{'foo', 'bar'}}, ... + 'HRF', struct('Variables', {{'foo', 'bar'}})); SPM.Sess(1).col = [1, 2]; @@ -247,75 +327,6 @@ function test_specifyContrasts_missing_condition() end -function test_specifyContrasts_subject_level() - - taskName = 'motion'; - - % GIVEN - DummyContrasts{1} = 'motion'; - DummyContrasts{2} = 'static'; - - Contrasts.Name = 'motion_gt_static'; - Contrasts.ConditionList = {'motion', 'static'}; - Contrasts.Weights = [1, -1]; - Contrasts.Test = 't'; - - model = BidsModel('init', true); - model.Nodes{2, 1} = BidsModel.empty_node('subject'); - model.Input.task = taskName; - model.Nodes{1, 1}.DummyContrasts.Contrasts = DummyContrasts; - model.Nodes{1, 1}.Contrasts{1} = Contrasts; - model.Nodes{2, 1}.GroupBy = {'subject', 'contrast'}; - model.Nodes{2, 1}.DummyContrasts = struct('Test', 't'); - model.Nodes{2, 1} = rmfield(model.Nodes{2}, 'Contrasts'); - model.Nodes{2, 1}.Model.X = 1; - - SPM.Sess(1).col = [1, 2]; - % skip Sess 2 to make sure contrast naming is based on the Sess number - SPM.Sess(3).col = [3, 4]; - SPM.Sess(4).col = [5, 6]; - - SPM.xX.name = { ... - ' motion*bf(1)' - ' static*bf(1)' - ' motion*bf(1)' - ' static*bf(1)' - ' motion*bf(1)' - ' static*bf(1)' - }; - - SPM.xX.X = ones(1, numel(SPM.xX.name)); - - % WHEN - contrasts = specifyContrasts(model, SPM); - - % THEN - names_contrast = { ... - 'motion_1', [1 0 0 0 0 0] - 'motion_3', [0 0 1 0 0 0] - 'motion_4', [0 0 0 0 1 0] - 'static_1', [0 1 0 0 0 0] - 'static_3', [0 0 0 1 0 0] - 'static_4', [0 0 0 0 0 1] - 'motion_gt_static_1', [1 -1 0 0 0 0] - 'motion_gt_static_3', [0 0 1 -1 0 0] - 'motion_gt_static_4', [0 0 0 0 1 -1] - 'motion', [1 0 1 0 1 0] - 'static', [0 1 0 1 0 1] - 'motion_gt_static', [1 -1 1 -1 1 -1] - }; - - assertEqual(numel(contrasts), size(names_contrast, 1)); - - for i = 1:size(names_contrast, 1) - expected(i).name = names_contrast{i, 1}; - expected(i).C = names_contrast{i, 2}; - expected(i).type = 't'; - assertEqual(contrasts(i), expected(i)); - end - -end - function test_specifyContrasts_complex() % % to test the generation of contrasts when there are several runs @@ -338,6 +349,10 @@ function test_specifyContrasts_complex() model.Nodes{1}.DummyContrasts.Contrasts = DummyContrasts; model.Nodes{1}.Contrasts{1} = Contrasts; model.Nodes{1}.Level = 'Run'; + model.Nodes{1}.Name = 'Run'; + model.Nodes{1}.Model = struct('X', {{'motion', 'static'}}, ... + 'HRF', struct('Variables', {{'motion', 'static'}})); + model.Nodes{1}.GroupBy = {'run', 'subject'}; SPM.Sess(1).col = [1, 2]; % skip Sess 2 to make sure contrast naming is based on the Sess number diff --git a/tests/tests_stats/subject_level/test_specifyDummyContrasts.m b/tests/tests_stats/subject_level/test_specifyDummyContrasts.m index 0e436b3a3..896516925 100644 --- a/tests/tests_stats/subject_level/test_specifyDummyContrasts.m +++ b/tests/tests_stats/subject_level/test_specifyDummyContrasts.m @@ -170,6 +170,6 @@ function test_specifyDummyContrasts_subselect_contrasts() contrasts = specifyDummyContrasts(model, node, contrasts, counter); - assertEqual(numel({contrasts.name}), 8); + assertEqual(numel({contrasts.name}), 20); end diff --git a/tests/tests_stats/subject_level/test_specifyDummyContrasts_Session.m b/tests/tests_stats/subject_level/test_specifyDummyContrasts_Session.m index a21717b5b..9a4d8b4d6 100644 --- a/tests/tests_stats/subject_level/test_specifyDummyContrasts_Session.m +++ b/tests/tests_stats/subject_level/test_specifyDummyContrasts_Session.m @@ -58,6 +58,9 @@ function test_specifyDummyContrasts_session() model.SPM = SPM; model.Nodes{1}.DummyContrasts.Contrasts{1} = 'sign_Stim1F'; + model.Nodes{1}.GroupBy = {'run', 'subject'}; + model.Nodes{1}.Model.X = {'sign_Stim1F', 'sign_Stim2F', 'no_resp'}; + model.Nodes{1}.Model.HRF.Variables = {'sign_Stim1F', 'sign_Stim2F', 'no_resp'}; model.Nodes{2, 1} = model.Nodes{1}; model.Nodes{end}.Name = 'Session'; @@ -71,7 +74,7 @@ function test_specifyDummyContrasts_session() contrasts = struct('C', [], 'name', []); counter = 0; contrasts = specifyDummyContrasts(model, node, contrasts, counter); - assertEqual(numel({contrasts.name}), 5); + assertEqual(numel({contrasts.name}), 11); node = model.Nodes{2}; contrasts = struct('C', [], 'name', []);