end2end_attention.m 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. function tests = end2end_attention
  2. % End-to-end test for attention dataset
  3. %__________________________________________________________________________
  4. % Copyright (C) 2018 Wellcome Centre for Human Neuroimaging
  5. % $Id: end2end_attention.m 7264 2018-02-22 14:43:47Z peter $
  6. tests = functiontests(localfunctions);
  7. % -------------------------------------------------------------------------
  8. function setupOnce(testCase)
  9. % Prepare path
  10. data_path = get_data_path();
  11. att_path = fullfile(data_path,'attention');
  12. if exist(att_path,'file')
  13. % Clear out existing analysis files
  14. P = spm_select('FPList', fullfile(att_path,'GLM'),'.*');
  15. for i = 1:size(P,1)
  16. spm_unlink(P(i,:));
  17. end
  18. else
  19. mkdir(att_path);
  20. end
  21. % Download dataset
  22. spm_get_dataset('spm', 'attention', '', data_path);
  23. % -------------------------------------------------------------------------
  24. function test_attention(testCase)
  25. % Run GLM
  26. run_glm();
  27. % Specify DCMs
  28. specify_dcms();
  29. % Select DCMs
  30. glm_dir = fullfile(get_data_path(), 'attention', 'GLM');
  31. P = {fullfile(glm_dir,'DCM_full.mat');
  32. fullfile(glm_dir,'DCM_fwd.mat');
  33. fullfile(glm_dir,'DCM_bwd.mat')};
  34. % Estimate DCMs (VL + BMR)
  35. clear matlabbatch;
  36. matlabbatch{1}.spm.dcm.estimate.dcms.subj.dcmmat = P;
  37. matlabbatch{1}.spm.dcm.estimate.output.single.dir = cellstr(glm_dir);
  38. matlabbatch{1}.spm.dcm.estimate.output.single.name = 'full_fwd_bwd';
  39. matlabbatch{1}.spm.dcm.estimate.est_type = 1;
  40. matlabbatch{1}.spm.dcm.estimate.fmri.analysis = 'time';
  41. spm_jobman('run',matlabbatch);
  42. % Load GCM
  43. gcm_file = fullfile(glm_dir,'GCM_full_fwd_bwd.mat');
  44. GCM = spm_dcm_load(gcm_file);
  45. % Compare models
  46. post = spm_dcm_bmc(GCM);
  47. % Check model 2 was the best
  48. [maxP,idx] = max(post);
  49. testCase.assertTrue(idx == 2);
  50. testCase.assertTrue(maxP > 0.9);
  51. % Check model fit (full model)
  52. GCM = spm_dcm_fmri_check(GCM,true);
  53. DCM = GCM{1};
  54. exp_var = DCM.diagnostics(1);
  55. max_A = DCM.diagnostics(2);
  56. testCase.assertTrue(exp_var > 85);
  57. testCase.assertTrue(max_A > 0.4);
  58. % Check the BOLD impulse response kernel looks sensible
  59. x = (1:DCM.M.N)*DCM.M.dt;
  60. y = DCM.H1(:,1,1);
  61. [max_y, idx] = max(y);
  62. max_x = x(idx);
  63. testCase.assertTrue(max_x > 5 & max_x < 7);
  64. testCase.assertTrue(max_y > 0);
  65. % -------------------------------------------------------------------------
  66. function run_glm()
  67. % Runs GLM and VOI extraction
  68. data_path = fullfile(get_data_path(), 'attention');
  69. % Initialise SPM
  70. spm('Defaults','fMRI');
  71. spm_jobman('initcfg');
  72. spm_get_defaults('cmdline',1);
  73. factors = load(fullfile(data_path,'factors.mat'));
  74. f = spm_select('FPList', fullfile(data_path,'functional'), '^snf.*\.img$');
  75. clear matlabbatch
  76. % OUTPUT DIRECTORY
  77. matlabbatch{1}.cfg_basicio.file_dir.dir_ops.cfg_mkdir.parent = cellstr(data_path);
  78. matlabbatch{1}.cfg_basicio.file_dir.dir_ops.cfg_mkdir.name = 'GLM';
  79. % MODEL SPECIFICATION
  80. matlabbatch{2}.spm.stats.fmri_spec.dir = cellstr(fullfile(data_path,'GLM'));
  81. matlabbatch{2}.spm.stats.fmri_spec.timing.units = 'scans';
  82. matlabbatch{2}.spm.stats.fmri_spec.timing.RT = 3.22;
  83. matlabbatch{2}.spm.stats.fmri_spec.sess.scans = cellstr(f);
  84. matlabbatch{2}.spm.stats.fmri_spec.sess.cond(1).name = 'Photic';
  85. matlabbatch{2}.spm.stats.fmri_spec.sess.cond(1).onset = [factors.att factors.natt factors.stat];
  86. matlabbatch{2}.spm.stats.fmri_spec.sess.cond(1).duration = 10;
  87. matlabbatch{2}.spm.stats.fmri_spec.sess.cond(2).name = 'Motion';
  88. matlabbatch{2}.spm.stats.fmri_spec.sess.cond(2).onset = [factors.att factors.natt];
  89. matlabbatch{2}.spm.stats.fmri_spec.sess.cond(2).duration = 10;
  90. matlabbatch{2}.spm.stats.fmri_spec.sess.cond(3).name = 'Attention';
  91. matlabbatch{2}.spm.stats.fmri_spec.sess.cond(3).onset = [factors.att];
  92. matlabbatch{2}.spm.stats.fmri_spec.sess.cond(3).duration = 10;
  93. % MODEL ESTIMATION
  94. matlabbatch{3}.spm.stats.fmri_est.spmmat = cellstr(fullfile(data_path,'GLM','SPM.mat'));
  95. % INFERENCE
  96. matlabbatch{4}.spm.stats.con.spmmat = cellstr(fullfile(data_path,'GLM','SPM.mat'));
  97. matlabbatch{4}.spm.stats.con.consess{1}.fcon.name = 'Effects of Interest';
  98. matlabbatch{4}.spm.stats.con.consess{1}.fcon.weights = eye(3);
  99. matlabbatch{4}.spm.stats.con.consess{2}.tcon.name = 'Photic';
  100. matlabbatch{4}.spm.stats.con.consess{2}.tcon.weights = [1 0 0];
  101. matlabbatch{4}.spm.stats.con.consess{3}.tcon.name = 'Motion';
  102. matlabbatch{4}.spm.stats.con.consess{3}.tcon.weights = [0 1 0];
  103. matlabbatch{4}.spm.stats.con.consess{4}.tcon.name = 'Attention';
  104. matlabbatch{4}.spm.stats.con.consess{4}.tcon.weights = [0 0 1];
  105. spm_jobman('run',matlabbatch);
  106. % VOLUMES OF INTEREST
  107. clear matlabbatch
  108. % EXTRACTING TIME SERIES: V5
  109. matlabbatch{1}.spm.util.voi.spmmat = cellstr(fullfile(data_path,'GLM','SPM.mat'));
  110. matlabbatch{1}.spm.util.voi.adjust = 1; % "effects of interest" F-contrast
  111. matlabbatch{1}.spm.util.voi.session = 1; % session 1
  112. matlabbatch{1}.spm.util.voi.name = 'V5';
  113. matlabbatch{1}.spm.util.voi.roi{1}.spm.spmmat = {''}; % using SPM.mat above
  114. matlabbatch{1}.spm.util.voi.roi{1}.spm.contrast = 3; % "Motion" T-contrast
  115. matlabbatch{1}.spm.util.voi.roi{1}.spm.threshdesc = 'FWE';
  116. matlabbatch{1}.spm.util.voi.roi{1}.spm.thresh = 0.05;
  117. matlabbatch{1}.spm.util.voi.roi{1}.spm.extent = 0;
  118. matlabbatch{1}.spm.util.voi.roi{1}.spm.mask.contrast = 4; % "Attention" T-contrast
  119. matlabbatch{1}.spm.util.voi.roi{1}.spm.mask.thresh = 0.05;
  120. matlabbatch{1}.spm.util.voi.roi{1}.spm.mask.mtype = 0; % inclusive
  121. matlabbatch{1}.spm.util.voi.roi{2}.sphere.centre = [-36 -87 -3];
  122. matlabbatch{1}.spm.util.voi.roi{2}.sphere.radius = 8;
  123. matlabbatch{1}.spm.util.voi.roi{2}.sphere.move.fixed = 1;
  124. matlabbatch{1}.spm.util.voi.expression = 'i1 & i2';
  125. % EXTRACTING TIME SERIES: V1
  126. matlabbatch{2}.spm.util.voi.spmmat = cellstr(fullfile(data_path,'GLM','SPM.mat'));
  127. matlabbatch{2}.spm.util.voi.adjust = 1; % "effects of interest" F-contrast
  128. matlabbatch{2}.spm.util.voi.session = 1; % session 1
  129. matlabbatch{2}.spm.util.voi.name = 'V1';
  130. matlabbatch{2}.spm.util.voi.roi{1}.spm.spmmat = {''}; % using SPM.mat above
  131. matlabbatch{2}.spm.util.voi.roi{1}.spm.contrast = 2; % "Photic" T-contrast
  132. matlabbatch{2}.spm.util.voi.roi{1}.spm.threshdesc = 'FWE';
  133. matlabbatch{2}.spm.util.voi.roi{1}.spm.thresh = 0.05;
  134. matlabbatch{2}.spm.util.voi.roi{1}.spm.extent = 0;
  135. matlabbatch{2}.spm.util.voi.roi{2}.sphere.centre = [0 -93 18];
  136. matlabbatch{2}.spm.util.voi.roi{2}.sphere.radius = 8;
  137. matlabbatch{2}.spm.util.voi.roi{2}.sphere.move.fixed = 1;
  138. matlabbatch{2}.spm.util.voi.expression = 'i1 & i2';
  139. % EXTRACTING TIME SERIES: SPC
  140. matlabbatch{3}.spm.util.voi.spmmat = cellstr(fullfile(data_path,'GLM','SPM.mat'));
  141. matlabbatch{3}.spm.util.voi.adjust = 1; % "effects of interest" F-contrast
  142. matlabbatch{3}.spm.util.voi.session = 1; % session 1
  143. matlabbatch{3}.spm.util.voi.name = 'SPC';
  144. matlabbatch{3}.spm.util.voi.roi{1}.spm.spmmat = {''}; % using SPM.mat above
  145. matlabbatch{3}.spm.util.voi.roi{1}.spm.contrast = 4; % "Attention" T-contrast
  146. matlabbatch{3}.spm.util.voi.roi{1}.spm.threshdesc = 'none';
  147. matlabbatch{3}.spm.util.voi.roi{1}.spm.thresh = 0.001;
  148. matlabbatch{3}.spm.util.voi.roi{1}.spm.extent = 0;
  149. matlabbatch{3}.spm.util.voi.roi{2}.sphere.centre = [-27 -84 36];
  150. matlabbatch{3}.spm.util.voi.roi{2}.sphere.radius = 8;
  151. matlabbatch{3}.spm.util.voi.roi{2}.sphere.move.fixed = 1;
  152. matlabbatch{3}.spm.util.voi.expression = 'i1 & i2';
  153. spm_jobman('run',matlabbatch);
  154. % -------------------------------------------------------------------------
  155. function specify_dcms()
  156. % SPM
  157. glm_dir = fullfile(get_data_path(),'attention','GLM');
  158. SPM = fullfile(glm_dir,'SPM.mat');
  159. % VOIs
  160. xY = {fullfile(glm_dir,'VOI_V1_1.mat');
  161. fullfile(glm_dir,'VOI_V5_1.mat');
  162. fullfile(glm_dir,'VOI_SPC_1.mat')};
  163. n = 3; % Num regions
  164. nu = 3; % Num inputs
  165. % Indices of regions & conditions
  166. V1 = 1;
  167. V5 = 2;
  168. SPC = 3;
  169. PHOTIC = 1;
  170. MOTION = 2;
  171. ATTENTION = 3;
  172. % Connectivity matrices
  173. a = ones(n,n);
  174. b = zeros(n,n,nu);
  175. c = zeros(n,nu);
  176. d = zeros(n,n,0);
  177. a(V1,SPC) = 0;
  178. a(SPC,V1) = 0;
  179. b(V5,V1,MOTION) = 1;
  180. b(V5,V1,ATTENTION) = 1;
  181. b(V1,V5,ATTENTION) = 1;
  182. c(V1,PHOTIC) = 1;
  183. % Specify model 1 (full)
  184. s = struct();
  185. s.name = 'full';
  186. s.u = [1 1 1]';
  187. s.delays = [3.22 3.22 3.22];
  188. s.TE = 0.04;
  189. s.nonlinear = false;
  190. s.two_state = false;
  191. s.stochastic = false;
  192. s.centre = false;
  193. s.induced = 0;
  194. s.a = a;
  195. s.b = b;
  196. s.c = c;
  197. s.d = d;
  198. spm_dcm_specify(SPM,xY,s);
  199. % Specify model 2 (fwd)
  200. b(V5,V1,ATTENTION) = 1;
  201. b(V1,V5,ATTENTION) = 0;
  202. s.name = 'fwd';
  203. s.b = b;
  204. spm_dcm_specify(SPM,xY,s);
  205. % Specify model 2 (bwd)
  206. b(V5,V1,ATTENTION) = 0;
  207. b(V1,V5,ATTENTION) = 1;
  208. s.name = 'bwd';
  209. s.b = b;
  210. spm_dcm_specify(SPM,xY,s);
  211. % -------------------------------------------------------------------------
  212. function data_path = get_data_path()
  213. data_path = fullfile( spm('Dir'), 'tests', ...
  214. 'output');