0001 function [fwd] = mne_read_forward_solution(fname,force_fixed,surf_ori,include,exclude)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059 me='MNE:mne_read_forward_solution';
0060
0061 global FIFF;
0062 if isempty(FIFF)
0063 FIFF = fiff_define_constants();
0064 end
0065
0066 if nargin == 1
0067 include = [];
0068 exclude = [];
0069 force_fixed = false;
0070 surf_ori = false;
0071 elseif nargin == 2
0072 include = [];
0073 exclude = [];
0074 surf_ori = false;
0075 elseif nargin == 3
0076 include = [];
0077 exclude = [];
0078 elseif nargin == 4
0079 exclude = [];
0080 elseif nargin ~= 5
0081 error(me,'Incorrect number of arguments');
0082 end
0083
0084
0085
0086 fprintf(1,'Reading forward solution from %s...\n',fname);
0087 [ fid, tree ] = fiff_open(fname);
0088
0089
0090
0091 fwds = fiff_dir_tree_find(tree,FIFF.FIFFB_MNE_FORWARD_SOLUTION);
0092 if isempty(fwds)
0093 fclose(fid);
0094 error(me,'No forward solutions in %s',fname);
0095 end
0096
0097
0098
0099 parent_mri = fiff_dir_tree_find(tree,FIFF.FIFFB_MNE_PARENT_MRI_FILE);
0100 if isempty(parent_mri)
0101 fclose(fid);
0102 error(me,'No parent MRI information in %s',fname);
0103 end
0104
0105
0106
0107 parent_meg = fiff_dir_tree_find(tree,FIFF.FIFFB_MNE_PARENT_MEAS_FILE);
0108 if isempty(parent_meg)
0109 fclose(fid);
0110 error(me,'No parent MEG information in %s',fname);
0111 end
0112 p = 0;
0113 for k = 1:parent_meg.nent
0114 kind = parent_meg.dir(k).kind;
0115 pos = parent_meg.dir(k).pos;
0116 if kind == FIFF.FIFF_CH_INFO
0117 p = p+1;
0118 tag = fiff_read_tag(fid,pos);
0119 chs(p) = tag.data;
0120 end
0121 end
0122
0123 try
0124 src = mne_read_source_spaces(fid,false,tree);
0125 catch
0126 fclose(fid);
0127 error(me,'Could not read the source spaces (%s)',mne_omit_first_line(lasterr));
0128 end
0129 for k = 1:length(src)
0130 src(k).id = mne_find_source_space_hemi(src(k));
0131 end
0132 fwd = [];
0133
0134
0135
0136 megnode = [];
0137 eegnode = [];
0138 for k = 1:length(fwds)
0139 tag = find_tag(fwds(k),FIFF.FIFF_MNE_INCLUDED_METHODS);
0140 if isempty(tag)
0141 fclose(fid);
0142 error(me,'Methods not listed for one of the forward solutions');
0143 end
0144 if tag.data == FIFF.FIFFV_MNE_MEG
0145 megnode = fwds(k);
0146 elseif tag.data == FIFF.FIFFV_MNE_EEG
0147 eegnode = fwds(k);
0148 end
0149 end
0150
0151 megfwd = read_one(megnode);
0152 if ~isempty(megfwd)
0153 if megfwd.source_ori == FIFF.FIFFV_MNE_FIXED_ORI
0154 ori = 'fixed';
0155 else
0156 ori = 'free';
0157 end
0158 fprintf(1,'\tRead MEG forward solution (%d sources, %d channels, %s orientations)\n',...
0159 megfwd.nsource,megfwd.nchan,ori);
0160 end
0161 eegfwd = read_one(eegnode);
0162 if ~isempty(eegfwd)
0163 if eegfwd.source_ori == FIFF.FIFFV_MNE_FIXED_ORI
0164 ori = 'fixed';
0165 else
0166 ori = 'free';
0167 end
0168 fprintf(1,'\tRead EEG forward solution (%d sources, %d channels, %s orientations)\n',...
0169 eegfwd.nsource,eegfwd.nchan,ori);
0170 end
0171
0172
0173
0174 if ~isempty(megfwd) && ~isempty(eegfwd)
0175 if size(megfwd.sol.data,2) ~= size(eegfwd.sol.data,2) || ...
0176 megfwd.source_ori ~= eegfwd.source_ori || ...
0177 megfwd.nsource ~= eegfwd.nsource || ...
0178 megfwd.coord_frame ~= eegfwd.coord_frame
0179 fclose(fid);
0180 error(me,'The MEG and EEG forward solutions do not match');
0181 end
0182 fwd = megfwd;
0183 fwd.sol.data = [ fwd.sol.data ; eegfwd.sol.data ];
0184 fwd.sol.nrow = fwd.sol.nrow + eegfwd.sol.nrow;
0185 fwd.sol.row_names = [ fwd.sol.row_names eegfwd.sol.row_names ];
0186 if ~isempty(fwd.sol_grad)
0187 fwd.sol_grad.data = [ fwd.sol_grad.data ; eegfwd.sol_grad.data ];
0188 fwd.sol_grad.nrow = fwd.sol_grad.nrow + eegfwd.sol_grad.nrow;
0189 fwd.sol_grad.row_names = [ fwd.sol_grad.row_names eegfwd.sol_grad.row_names ];
0190 end
0191 fwd.nchan = fwd.nchan + eegfwd.nchan;
0192 fprintf(1,'\tMEG and EEG forward solutions combined\n');
0193 elseif ~isempty(megfwd)
0194 fwd = megfwd;
0195 else
0196 fwd = eegfwd;
0197 end
0198 clear('megfwd');
0199 clear('eegfwd');
0200
0201
0202
0203 tag = find_tag(parent_mri,FIFF.FIFF_COORD_TRANS);
0204 if isempty(tag)
0205 fclose(fid);
0206 error(me,'MRI/head coordinate transformation not found');
0207 else
0208 mri_head_t = tag.data;
0209 if mri_head_t.from ~= FIFF.FIFFV_COORD_MRI || mri_head_t.to ~= FIFF.FIFFV_COORD_HEAD
0210 mri_head_t = fiff_invert_transform(mri_head_t);
0211 if mri_head_t.from ~= FIFF.FIFFV_COORD_MRI || mri_head_t.to ~= FIFF.FIFFV_COORD_HEAD
0212 fclose(fid);
0213 error(me,'MRI/head coordinate transformation not found');
0214 end
0215 end
0216 end
0217 fclose(fid);
0218
0219 fwd.mri_head_t = mri_head_t;
0220
0221
0222
0223
0224 if fwd.coord_frame ~= FIFF.FIFFV_COORD_MRI && ...
0225 fwd.coord_frame ~= FIFF.FIFFV_COORD_HEAD
0226 error(me,'Only forward solutions computed in MRI or head coordinates are acceptable');
0227 end
0228
0229 nuse = 0;
0230 for k = 1:length(src)
0231 try
0232 src(k) = mne_transform_source_space_to(src(k),fwd.coord_frame,mri_head_t);
0233 catch
0234 error(me,'Could not transform source space (%s)',mne_omit_first_line(lasterr));
0235 end
0236 nuse = nuse + src(k).nuse;
0237 end
0238 if nuse ~= fwd.nsource
0239 error(me,'Source spaces do not match the forward solution.\n');
0240 end
0241 fprintf(1,'\tSource spaces transformed to the forward solution coordinate frame\n');
0242 fwd.src = src;
0243
0244
0245
0246 if fwd.source_ori == FIFF.FIFFV_MNE_FIXED_ORI || ...
0247 force_fixed == true
0248 nuse = 0;
0249 fwd.source_rr = zeros(fwd.nsource,3);
0250 fwd.source_nn = zeros(fwd.nsource,3);
0251 for k = 1:length(src)
0252 fwd.source_rr(nuse+1:nuse+src(k).nuse,:) = src(k).rr(src(k).vertno,:);
0253 fwd.source_nn(nuse+1:nuse+src(k).nuse,:) = src(k).nn(src(k).vertno,:);
0254 nuse = nuse + src(k).nuse;
0255 end
0256
0257
0258
0259 if fwd.source_ori ~= FIFF.FIFFV_MNE_FIXED_ORI
0260 fprintf(1,'\tChanging to fixed-orientation forward solution...');
0261 fix_rot = mne_block_diag(fwd.source_nn',1);
0262 fwd.sol.data = fwd.sol.data*fix_rot;
0263 fwd.sol.ncol = fwd.nsource;
0264 fwd.source_ori = FIFF.FIFFV_MNE_FIXED_ORI;
0265
0266 if ~isempty(fwd.sol_grad)
0267 fwd.sol_grad.data = fwd.sol_grad.data*kron(fix_rot,eye(3));
0268 fwd.sol_grad.ncol = 3*fwd.nsource;
0269 end
0270 fprintf(1,'[done]\n');
0271 end
0272 else
0273 if surf_ori
0274
0275
0276
0277 fprintf(1,'\tConverting to surface-based source orientations...');
0278 nuse = 0;
0279 pp = 1;
0280 fwd.source_rr = zeros(fwd.nsource,3);
0281 for k = 1:length(src)
0282 fwd.source_rr(nuse+1:nuse+src(k).nuse,:) = src(k).rr(src(k).vertno,:);
0283 for p = 1:src(k).nuse
0284
0285
0286
0287 nn = src(k).nn(src(k).vertno(p),:)';
0288 [ U, S, V ] = svd(eye(3,3) - nn*nn');
0289
0290
0291
0292 if nn'*U(:,3) < 0
0293 U = -U;
0294 end
0295 fwd.source_nn(pp:pp+2,:) = U';
0296 pp = pp + 3;
0297 end
0298 nuse = nuse + src(k).nuse;
0299 end
0300 surf_rot = mne_block_diag(fwd.source_nn',3);
0301 fwd.sol.data = fwd.sol.data*surf_rot;
0302 if ~isempty(fwd.sol_grad)
0303 fwd.sol_grad.data = fwd.sol_grad.data*kron(surf_rot,eye(3));
0304 end
0305 fprintf(1,'[done]\n');
0306 else
0307 fprintf(1,'\tCartesian source orientations...');
0308 nuse = 0;
0309 fwd.source_rr = zeros(fwd.nsource,3);
0310 for k = 1:length(src)
0311 fwd.source_rr(nuse+1:nuse+src(k).nuse,:) = src(k).rr(src(k).vertno,:);
0312 nuse = nuse + src(k).nuse;
0313 end
0314 fwd.source_nn = kron(ones(fwd.nsource,1),eye(3,3));
0315 fprintf(1,'[done]\n');
0316 end
0317 end
0318
0319
0320
0321 fwd.chs = chs;
0322
0323
0324
0325 if ~isempty(include) || ~isempty(exclude)
0326
0327
0328
0329 if isempty(include)
0330 pick = ones(1,fwd.nchan);
0331 else
0332 pick = zeros(1,fwd.nchan);
0333 for k = 1:size(include,2)
0334 c = strmatch(include{k},fwd.sol.row_names,'exact');
0335 for p = 1:length(c)
0336 pick(c(p)) = 1;
0337 end
0338 end
0339 end
0340
0341
0342
0343 if ~isempty(exclude)
0344 for k = 1:length(exclude)
0345 c = strmatch(exclude{k},fwd.sol.row_names,'exact');
0346 for p = 1:length(c)
0347 pick(c(p)) = 0;
0348 end
0349 end
0350 end
0351
0352
0353
0354 nuse = sum(pick);
0355 if nuse == 0
0356 error(me,'Nothing remains after picking');
0357 end
0358
0359
0360
0361 sel = zeros(1,nuse);
0362 p = 0;
0363 for k = 1:fwd.nchan
0364 if pick(k) > 0
0365 p = p + 1;
0366 sel(p) = k;
0367 end
0368 end
0369 fprintf(1,'\t%d out of %d channels remain after picking\n',nuse,fwd.nchan);
0370
0371
0372
0373 fwd.nchan = nuse;
0374 fwd.sol.data = fwd.sol.data(sel,:);
0375 fwd.sol.nrow = nuse;
0376 fwd.sol.row_names = fwd.sol.row_names(sel);
0377
0378 if ~isempty(fwd.sol_grad)
0379 fwd.sol_grad.data = fwd.sol_grad.data(sel,:);
0380 fwd.sol_grad.nrow = nuse;
0381 fwd.sol_grad.row_names = fwd.sol_grad.row_names(sel);
0382 end
0383
0384 fwd.chs = fwd.chs(sel);
0385 end
0386
0387 return;
0388
0389 function [tag] = find_tag(nodes,findkind)
0390
0391 for kk = 1:length(nodes)
0392 node = nodes(kk);
0393 for p = 1:node.nent
0394 if node.dir(p).kind == findkind
0395 tag = fiff_read_tag(fid,node.dir(p).pos);
0396 return;
0397 end
0398 end
0399 tag = [];
0400 return;
0401 end
0402
0403 end
0404
0405 function [one] = read_one(node)
0406
0407
0408
0409 if isempty(node)
0410 one = [];
0411 return;
0412 end
0413 tag = find_tag(node,FIFF.FIFF_MNE_SOURCE_ORIENTATION);
0414 if isempty(tag)
0415 fclose(fid);
0416 error(me,'Source orientation tag not found');
0417 end
0418 one.source_ori = tag.data;
0419 tag = find_tag(node,FIFF.FIFF_MNE_COORD_FRAME);
0420 if isempty(tag)
0421 fclose(fid);
0422 error(me,'Coordinate frame tag not found');
0423 end
0424 one.coord_frame = tag.data;
0425 tag = find_tag(node,FIFF.FIFF_MNE_SOURCE_SPACE_NPOINTS);
0426 if isempty(tag)
0427 fclose(fid);
0428 error(me,'Number of sources not found');
0429 end
0430 one.nsource = tag.data;
0431 tag = find_tag(node,FIFF.FIFF_NCHAN);
0432 if isempty(tag)
0433 fclose(fid);
0434 error(me,'Number of channels not found');
0435 end
0436 one.nchan = tag.data;
0437 try
0438 one.sol = mne_transpose_named_matrix(fiff_read_named_matrix(fid,node,FIFF.FIFF_MNE_FORWARD_SOLUTION));
0439 catch
0440 fclose(fid);
0441 error(me,'Forward solution data not found (%s)',mne_omit_first_line(lasterr));
0442 end
0443 try
0444 one.sol_grad = mne_transpose_named_matrix(fiff_read_named_matrix(fid,node,FIFF.FIFF_MNE_FORWARD_SOLUTION_GRAD));
0445 catch
0446 one.sol_grad = [];
0447 end
0448 if size(one.sol.data,1) ~= one.nchan || ...
0449 (size(one.sol.data,2) ~= one.nsource && size(one.sol.data,2) ~= 3*one.nsource)
0450 fclose(fid);
0451 error(me,'Forward solution matrix has wrong dimensions');
0452 end
0453 if ~isempty(one.sol_grad)
0454 if size(one.sol_grad.data,1) ~= one.nchan || ...
0455 (size(one.sol_grad.data,2) ~= 3*one.nsource && size(one.sol_grad.data,2) ~= 3*3*one.nsource)
0456 fclose(fid);
0457 error(me,'Forward solution gradient matrix has wrong dimensions');
0458 end
0459 end
0460 return;
0461 end
0462
0463 end