MNE-CPP 0.1.9
A Framework for Electrophysiology
Loading...
Searching...
No Matches
mne_inverse_operator.cpp
Go to the documentation of this file.
1//=============================================================================================================
38//=============================================================================================================
39// INCLUDES
40//=============================================================================================================
41
43#include <fs/label.h>
44
45#include <iostream>
46
47//=============================================================================================================
48// QT INCLUDES
49//=============================================================================================================
50
51#include <QFuture>
52#include <QtConcurrent>
53
54//=============================================================================================================
55// EIGEN INCLUDES
56//=============================================================================================================
57
58#include <Eigen/SVD>
59
60//=============================================================================================================
61// USED NAMESPACES
62//=============================================================================================================
63
64using namespace UTILSLIB;
65using namespace MNELIB;
66using namespace FIFFLIB;
67using namespace FSLIB;
68using namespace Eigen;
69
70//=============================================================================================================
71// DEFINE MEMBER METHODS
72//=============================================================================================================
73
75: methods(-1)
76, source_ori(-1)
77, nsource(-1)
78, nchan(-1)
79, coord_frame(-1)
80, eigen_leads_weighted(false)
81, eigen_leads(new FiffNamedMatrix)
82, eigen_fields(new FiffNamedMatrix)
83, noise_cov(new FiffCov)
84, source_cov(new FiffCov)
85, orient_prior(new FiffCov)
86, depth_prior(new FiffCov)
87, fmri_prior(new FiffCov)
88, nave(-1)
89{
90 qRegisterMetaType<QSharedPointer<MNELIB::MNEInverseOperator> >("QSharedPointer<MNELIB::MNEInverseOperator>");
91 qRegisterMetaType<MNELIB::MNEInverseOperator>("MNELIB::MNEInverseOperator");
92}
93
94//=============================================================================================================
95
97{
99 qRegisterMetaType<QSharedPointer<MNELIB::MNEInverseOperator> >("QSharedPointer<MNELIB::MNEInverseOperator>");
100 qRegisterMetaType<MNELIB::MNEInverseOperator>("MNELIB::MNEInverseOperator");
101}
102
103//=============================================================================================================
104
106 const MNEForwardSolution& forward,
107 const FiffCov& p_noise_cov,
108 float loose,
109 float depth,
110 bool fixed,
111 bool limit_depth_chs)
112{
113 *this = MNEInverseOperator::make_inverse_operator(info, forward, p_noise_cov, loose, depth, fixed, limit_depth_chs);
114 qRegisterMetaType<QSharedPointer<MNELIB::MNEInverseOperator> >("QSharedPointer<MNELIB::MNEInverseOperator>");
115 qRegisterMetaType<MNELIB::MNEInverseOperator>("MNELIB::MNEInverseOperator");
116}
117
118//=============================================================================================================
119
121: info(p_MNEInverseOperator.info)
122, methods(p_MNEInverseOperator.methods)
123, source_ori(p_MNEInverseOperator.source_ori)
124, nsource(p_MNEInverseOperator.nsource)
125, nchan(p_MNEInverseOperator.nchan)
126, coord_frame(p_MNEInverseOperator.coord_frame)
127, source_nn(p_MNEInverseOperator.source_nn)
128, sing(p_MNEInverseOperator.sing)
129, eigen_leads_weighted(p_MNEInverseOperator.eigen_leads_weighted)
130, eigen_leads(p_MNEInverseOperator.eigen_leads)
131, eigen_fields(p_MNEInverseOperator.eigen_fields)
132, noise_cov(p_MNEInverseOperator.noise_cov)
133, source_cov(p_MNEInverseOperator.source_cov)
134, orient_prior(p_MNEInverseOperator.orient_prior)
135, depth_prior(p_MNEInverseOperator.depth_prior)
136, fmri_prior(p_MNEInverseOperator.fmri_prior)
137, src(p_MNEInverseOperator.src)
138, mri_head_t(p_MNEInverseOperator.mri_head_t)
139, nave(p_MNEInverseOperator.nave)
140, projs(p_MNEInverseOperator.projs)
141, proj(p_MNEInverseOperator.proj)
142, whitener(p_MNEInverseOperator.whitener)
143, reginv(p_MNEInverseOperator.reginv)
144, noisenorm(p_MNEInverseOperator.noisenorm)
145{
146 qRegisterMetaType<QSharedPointer<MNELIB::MNEInverseOperator> >("QSharedPointer<MNELIB::MNEInverseOperator>");
147 qRegisterMetaType<MNELIB::MNEInverseOperator>("MNELIB::MNEInverseOperator");
148}
149
150//=============================================================================================================
151
155
156//=============================================================================================================
157
159 QString method,
160 bool pick_normal,
161 MatrixXd &K,
162 SparseMatrix<double> &noise_norm,
163 QList<VectorXi> &vertno)
164{
165 MatrixXd t_eigen_leads = this->eigen_leads->data;
166 MatrixXd t_source_cov = this->source_cov->data;
167 if(method.compare("MNE") != 0)
168 noise_norm = this->noisenorm;
169
170 vertno = this->src.get_vertno();
171
172 typedef Eigen::Triplet<double> T;
173 std::vector<T> tripletList;
174
175 if(!label.isEmpty())
176 {
177 qDebug() << "ToDo: Label selection needs to be debugged - not done jet!";
178 VectorXi src_sel;
179 vertno = this->src.label_src_vertno_sel(label, src_sel);
180
181 if(method.compare("MNE") != 0)
182 {
183 tripletList.clear();
184 tripletList.reserve(noise_norm.nonZeros());
185
186 for (qint32 k = 0; k < noise_norm.outerSize(); ++k)
187 {
188 for (SparseMatrix<double>::InnerIterator it(noise_norm,k); it; ++it)
189 {
190 //ToDo bad search - increase speed by using stl search
191 qint32 row = -1;
192 for(qint32 i = 0; i < src_sel.size(); ++i)
193 if(src_sel[i] == it.row())
194 row = i;
195 if(row != -1)
196 tripletList.push_back(T(it.row(), it.col(), it.value()));
197 }
198 }
199
200 noise_norm = SparseMatrix<double>(src_sel.size(),noise_norm.cols());
201 noise_norm.setFromTriplets(tripletList.begin(), tripletList.end());
202 }
203
204 if(this->source_ori == FIFFV_MNE_FREE_ORI)
205 {
206 VectorXi src_sel_new(src_sel.size()*3);
207
208 for(qint32 i = 0; i < src_sel.size(); ++i)
209 {
210 src_sel_new[i*3] = src_sel[i]*3;
211 src_sel_new[i*3+1] = src_sel[i]*3+1;
212 src_sel_new[i*3+2] = src_sel[i]*3+2;
213 }
214 src_sel = src_sel_new;
215 }
216
217 for(qint32 i = 0; i < src_sel.size(); ++i)
218 {
219 t_eigen_leads.row(i) = t_eigen_leads.row(src_sel[i]);
220 t_source_cov = t_source_cov.row(src_sel[i]);
221 }
222 t_eigen_leads.conservativeResize(src_sel.size(), t_eigen_leads.cols());
223 t_source_cov.conservativeResize(src_sel.size(), t_source_cov.cols());
224 }
225
226 if(pick_normal)
227 {
228 if(this->source_ori != FIFFV_MNE_FREE_ORI)
229 {
230 qWarning("Warning: Pick normal can only be used with a free orientation inverse operator.\n");
231 return false;
232 }
233
234 bool is_loose = ((0 < this->orient_prior->data(0,0)) && (this->orient_prior->data(0,0) < 1)) ? true : false;
235 if(!is_loose)
236 {
237 qWarning("The pick_normal parameter is only valid when working with loose orientations.\n");
238 return false;
239 }
240
241 // keep only the normal components
242 qint32 count = 0;
243 for(qint32 i = 2; i < t_eigen_leads.rows(); i+=3)
244 {
245 t_eigen_leads.row(count) = t_eigen_leads.row(i);
246 ++count;
247 }
248 t_eigen_leads.conservativeResize(count, t_eigen_leads.cols());
249
250 count = 0;
251 for(qint32 i = 2; i < t_source_cov.rows(); i+=3)
252 {
253 t_source_cov.row(count) = t_source_cov.row(i);
254 ++count;
255 }
256 t_source_cov.conservativeResize(count, t_source_cov.cols());
257 }
258
259 tripletList.clear();
260 tripletList.reserve(reginv.rows());
261 for(qint32 i = 0; i < reginv.rows(); ++i)
262 tripletList.push_back(T(i, i, reginv(i,0)));
263 SparseMatrix<double> t_reginv(reginv.rows(),reginv.rows());
264 t_reginv.setFromTriplets(tripletList.begin(), tripletList.end());
265
266 MatrixXd trans = t_reginv*eigen_fields->data*whitener*proj;
267 //
268 // Transformation into current distributions by weighting the eigenleads
269 // with the weights computed above
270 //
272 {
273 //
274 // R^0.5 has been already factored in
275 //
276 printf("(eigenleads already weighted)...\n");
277 K = t_eigen_leads*trans;
278 }
279 else
280 {
281 //
282 // R^0.5 has to factored in
283 //
284 printf("(eigenleads need to be weighted)...\n");
285
286 std::vector<T> tripletList2;
287 tripletList2.reserve(t_source_cov.rows());
288 for(qint32 i = 0; i < t_source_cov.rows(); ++i)
289 tripletList2.push_back(T(i, i, sqrt(t_source_cov(i,0))));
290 SparseMatrix<double> t_sourceCov(t_source_cov.rows(),t_source_cov.rows());
291 t_sourceCov.setFromTriplets(tripletList2.begin(), tripletList2.end());
292
293 K = t_sourceCov*t_eigen_leads*trans;
294 }
295
296 if(method.compare("MNE") == 0)
297 noise_norm = SparseMatrix<double>();
298
299 //store assembled kernel
300 m_K = K;
301
302 return true;
303}
304
305//=============================================================================================================
306
308{
309 QStringList inv_ch_names = this->eigen_fields->col_names;
310
311 bool t_bContains = true;
312 if(this->eigen_fields->col_names.size() != this->noise_cov->names.size())
313 t_bContains = false;
314 else
315 {
316 for(qint32 i = 0; i < this->noise_cov->names.size(); ++i)
317 {
318 if(inv_ch_names[i] != this->noise_cov->names[i])
319 {
320 t_bContains = false;
321 break;
322 }
323 }
324 }
325
326 if(!t_bContains)
327 {
328 qCritical("Channels in inverse operator eigen fields do not match noise covariance channels.");
329 return false;
330 }
331
332 QStringList data_ch_names = info.ch_names;
333
334 QStringList missing_ch_names;
335 for(qint32 i = 0; i < inv_ch_names.size(); ++i)
336 if(!data_ch_names.contains(inv_ch_names[i]))
337 missing_ch_names.append(inv_ch_names[i]);
338
339 qint32 n_missing = missing_ch_names.size();
340
341 if(n_missing > 0)
342 {
343 qCritical() << n_missing << "channels in inverse operator are not present in the data (" << missing_ch_names << ")";
344 return false;
345 }
346
347 return true;
348}
349
350//=============================================================================================================
351
352MatrixXd MNEInverseOperator::cluster_kernel(const AnnotationSet &p_AnnotationSet, qint32 p_iClusterSize, MatrixXd& p_D, QString p_sMethod) const
353{
354 printf("Cluster kernel using %s.\n", p_sMethod.toUtf8().constData());
355
356 MatrixXd p_outMT = this->m_K.transpose();
357
358 QList<MNEClusterInfo> t_qListMNEClusterInfo;
359 MNEClusterInfo t_MNEClusterInfo;
360 t_qListMNEClusterInfo.append(t_MNEClusterInfo);
361 t_qListMNEClusterInfo.append(t_MNEClusterInfo);
362
363 //
364 // Check consisty
365 //
366 if(this->isFixedOrient())
367 {
368 printf("Error: Fixed orientation not implemented jet!\n");
369 return p_outMT;
370 }
371
372// qDebug() << "p_outMT" << p_outMT.rows() << "x" << p_outMT.cols();
373
374// MatrixXd t_G_Whitened(0,0);
375// bool t_bUseWhitened = false;
376// //
377// //Whiten gain matrix before clustering -> cause diffenerent units Magnetometer, Gradiometer and EEG
378// //
379// if(!p_pNoise_cov.isEmpty() && !p_pInfo.isEmpty())
380// {
381// FiffInfo p_outFwdInfo;
382// FiffCov p_outNoiseCov;
383// MatrixXd p_outWhitener;
384// qint32 p_outNumNonZero;
385// //do whitening with noise cov
386// this->prepare_forward(p_pInfo, p_pNoise_cov, false, p_outFwdInfo, t_G_Whitened, p_outNoiseCov, p_outWhitener, p_outNumNonZero);
387// printf("\tWhitening the forward solution.\n");
388
389// t_G_Whitened = p_outWhitener*t_G_Whitened;
390// t_bUseWhitened = true;
391// }
392
393 //
394 // Assemble input data
395 //
396 qint32 count;
397 qint32 offset;
398
399 MatrixXd t_MT_new;
400
401 for(qint32 h = 0; h < this->src.size(); ++h )
402 {
403
404 count = 0;
405 offset = 0;
406
407 // Offset for continuous indexing;
408 if(h > 0)
409 for(qint32 j = 0; j < h; ++j)
410 offset += this->src[j].nuse;
411
412 if(h == 0)
413 printf("Cluster Left Hemisphere\n");
414 else
415 printf("Cluster Right Hemisphere\n");
416
417 Colortable t_CurrentColorTable = p_AnnotationSet[h].getColortable();
418 VectorXi label_ids = t_CurrentColorTable.getLabelIds();
419
420 // Get label ids for every vertex
421 VectorXi vertno_labeled = VectorXi::Zero(this->src[h].vertno.rows());
422
423 //ToDo make this more universal -> using Label instead of annotations - obsolete when using Labels
424 for(qint32 i = 0; i < vertno_labeled.rows(); ++i)
425 vertno_labeled[i] = p_AnnotationSet[h].getLabelIds()[this->src[h].vertno[i]];
426
427 //Qt Concurrent List
428 QList<RegionMT> m_qListRegionMTIn;
429
430 //
431 // Generate cluster input data
432 //
433 for (qint32 i = 0; i < label_ids.rows(); ++i)
434 {
435 if (label_ids[i] != 0)
436 {
437 QString curr_name = t_CurrentColorTable.struct_names[i];//obj.label2AtlasName(label(i));
438 printf("\tCluster %d / %ld %s...", i+1, label_ids.rows(), curr_name.toUtf8().constData());
439
440 //
441 // Get source space indeces
442 //
443 VectorXi idcs = VectorXi::Zero(vertno_labeled.rows());
444 qint32 c = 0;
445
446 //Select ROIs //change this use label info with a hash tabel
447 for(qint32 j = 0; j < vertno_labeled.rows(); ++j)
448 {
449 if(vertno_labeled[j] == label_ids[i])
450 {
451 idcs[c] = j;
452 ++c;
453 }
454 }
455 idcs.conservativeResize(c);
456
457 //get selected MT
458 MatrixXd t_MT(p_outMT.rows(), idcs.rows()*3);
459
460 for(qint32 j = 0; j < idcs.rows(); ++j)
461 t_MT.block(0, j*3, t_MT.rows(), 3) = p_outMT.block(0, (idcs[j]+offset)*3, t_MT.rows(), 3);
462
463 qint32 nSens = t_MT.rows();
464 qint32 nSources = t_MT.cols()/3;
465
466 if (nSources > 0)
467 {
468 RegionMT t_sensMT;
469
470 t_sensMT.idcs = idcs;
471 t_sensMT.iLabelIdxIn = i;
472 t_sensMT.nClusters = ceil((double)nSources/(double)p_iClusterSize);
473
474 t_sensMT.matRoiMTOrig = t_MT;
475
476 printf("%d Cluster(s)... ", t_sensMT.nClusters);
477
478 // Reshape Input data -> sources rows; sensors columns
479 t_sensMT.matRoiMT = MatrixXd(t_MT.cols()/3, 3*nSens);
480
481 for(qint32 j = 0; j < nSens; ++j)
482 for(qint32 k = 0; k < t_sensMT.matRoiMT.rows(); ++k)
483 t_sensMT.matRoiMT.block(k,j*3,1,3) = t_MT.block(j,k*3,1,3);
484
485 t_sensMT.sDistMeasure = p_sMethod;
486
487 m_qListRegionMTIn.append(t_sensMT);
488
489 printf("[added]\n");
490 }
491 else
492 {
493 printf("failed! Label contains no sources.\n");
494 }
495 }
496 }
497
498 //
499 // Calculate clusters
500 //
501 printf("Clustering... ");
502 QFuture< RegionMTOut > res;
503 res = QtConcurrent::mapped(m_qListRegionMTIn, &RegionMT::cluster);
504 res.waitForFinished();
505
506 //
507 // Assign results
508 //
509 MatrixXd t_MT_partial;
510
511 qint32 nClusters;
512 qint32 nSens;
513 QList<RegionMT>::const_iterator itIn;
514 itIn = m_qListRegionMTIn.begin();
515 QFuture<RegionMTOut>::const_iterator itOut;
516 for (itOut = res.constBegin(); itOut != res.constEnd(); ++itOut)
517 {
518 nClusters = itOut->ctrs.rows();
519 nSens = itOut->ctrs.cols()/3;
520 t_MT_partial = MatrixXd::Zero(nSens, nClusters*3);
521
522// std::cout << "Number of Clusters: " << nClusters << " x " << nSens << std::endl;//itOut->iLabelIdcsOut << std::endl;
523
524 //
525 // Assign the centroid for each cluster to the partial G
526 //
527 //ToDo change this use indeces found with whitened data
528 for(qint32 j = 0; j < nSens; ++j)
529 for(qint32 k = 0; k < nClusters; ++k)
530 t_MT_partial.block(j, k*3, 1, 3) = itOut->ctrs.block(k,j*3,1,3);
531
532 //
533 // Get cluster indizes and its distances to the centroid
534 //
535 for(qint32 j = 0; j < nClusters; ++j)
536 {
537 VectorXi clusterIdcs = VectorXi::Zero(itOut->roiIdx.rows());
538 VectorXd clusterDistance = VectorXd::Zero(itOut->roiIdx.rows());
539 qint32 nClusterIdcs = 0;
540 for(qint32 k = 0; k < itOut->roiIdx.rows(); ++k)
541 {
542 if(itOut->roiIdx[k] == j)
543 {
544 clusterIdcs[nClusterIdcs] = itIn->idcs[k];
545// qint32 offset = h == 0 ? 0 : this->src[0].nuse;
546// Q_UNUSED(offset)
547 clusterDistance[nClusterIdcs] = itOut->D(k,j);
548 ++nClusterIdcs;
549 }
550 }
551 clusterIdcs.conservativeResize(nClusterIdcs);
552 clusterDistance.conservativeResize(nClusterIdcs);
553
554 VectorXi clusterVertnos = VectorXi::Zero(clusterIdcs.size());
555 for(qint32 k = 0; k < clusterVertnos.size(); ++k)
556 clusterVertnos(k) = this->src[h].vertno[clusterIdcs(k)];
557
558 t_qListMNEClusterInfo[h].clusterVertnos.append(clusterVertnos);
559
560 }
561
562 //
563 // Assign partial G to new LeadField
564 //
565 if(t_MT_partial.rows() > 0 && t_MT_partial.cols() > 0)
566 {
567 t_MT_new.conservativeResize(t_MT_partial.rows(), t_MT_new.cols() + t_MT_partial.cols());
568 t_MT_new.block(0, t_MT_new.cols() - t_MT_partial.cols(), t_MT_new.rows(), t_MT_partial.cols()) = t_MT_partial;
569
570 // Map the centroids to the closest rr
571 for(qint32 k = 0; k < nClusters; ++k)
572 {
573 qint32 j = 0;
574
575 double sqec = sqrt((itIn->matRoiMTOrig.block(0, j*3, itIn->matRoiMTOrig.rows(), 3) - t_MT_partial.block(0, k*3, t_MT_partial.rows(), 3)).array().pow(2).sum());
576 double sqec_min = sqec;
577 qint32 j_min = 0;
578// MatrixXd matGainDiff;
579 for(qint32 j = 1; j < itIn->idcs.rows(); ++j)
580 {
581 sqec = sqrt((itIn->matRoiMTOrig.block(0, j*3, itIn->matRoiMTOrig.rows(), 3) - t_MT_partial.block(0, k*3, t_MT_partial.rows(), 3)).array().pow(2).sum());
582
583 if(sqec < sqec_min)
584 {
585 sqec_min = sqec;
586 j_min = j;
587// matGainDiff = itIn->matRoiGOrig.block(0, j*3, itIn->matRoiGOrig.rows(), 3) - t_G_partial.block(0, k*3, t_G_partial.rows(), 3);
588 }
589 }
590 (void)j_min; // squash compiler warning, set but unused
591
592
593// qListGainDist.append(matGainDiff);
594
595 // Take the closest coordinates
596// qint32 sel_idx = itIn->idcs[j_min];
597// Q_UNUSED(sel_idx)
598
599// //vertices
600// std::cout << this->src[h].vertno[sel_idx] << ", ";
601
602 ++count;
603 }
604 }
605
606 ++itIn;
607 }
608
609 printf("[done]\n");
610 }
611
612 //
613 // Cluster operator D (sources x clusters)
614 //
615 qint32 totalNumOfClust = 0;
616 for (qint32 h = 0; h < 2; ++h)
617 totalNumOfClust += t_qListMNEClusterInfo[h].clusterVertnos.size();
618
619 if(this->isFixedOrient())
620 p_D = MatrixXd::Zero(p_outMT.cols(), totalNumOfClust);
621 else
622 p_D = MatrixXd::Zero(p_outMT.cols(), totalNumOfClust*3);
623
624 QList<VectorXi> t_vertnos = this->src.get_vertno();
625
626// qDebug() << "Size: " << t_vertnos[0].size() << t_vertnos[1].size();
627// qDebug() << "this->sol->data.cols(): " << this->sol->data.cols();
628
629 qint32 currentCluster = 0;
630 for (qint32 h = 0; h < 2; ++h)
631 {
632 int hemiOffset = h == 0 ? 0 : t_vertnos[0].size();
633 for(qint32 i = 0; i < t_qListMNEClusterInfo[h].clusterVertnos.size(); ++i)
634 {
635 VectorXi idx_sel;
636 MNEMath::intersect(t_vertnos[h], t_qListMNEClusterInfo[h].clusterVertnos[i], idx_sel);
637
638// std::cout << "\nVertnos:\n" << t_vertnos[h] << std::endl;
639
640// std::cout << "clusterVertnos[i]:\n" << t_qListMNEClusterInfo[h].clusterVertnos[i] << std::endl;
641
642 idx_sel.array() += hemiOffset;
643
644// std::cout << "idx_sel]:\n" << idx_sel << std::endl;
645
646 double selectWeight = 1.0/idx_sel.size();
647 if(this->isFixedOrient())
648 {
649 for(qint32 j = 0; j < idx_sel.size(); ++j)
650 p_D.col(currentCluster)[idx_sel(j)] = selectWeight;
651 }
652 else
653 {
654 qint32 clustOffset = currentCluster*3;
655 for(qint32 j = 0; j < idx_sel.size(); ++j)
656 {
657 qint32 idx_sel_Offset = idx_sel(j)*3;
658 //x
659 p_D(idx_sel_Offset,clustOffset) = selectWeight;
660 //y
661 p_D(idx_sel_Offset+1, clustOffset+1) = selectWeight;
662 //z
663 p_D(idx_sel_Offset+2, clustOffset+2) = selectWeight;
664 }
665 }
666 ++currentCluster;
667 }
668 }
669
670// std::cout << "D:\n" << D.row(0) << std::endl << D.row(1) << std::endl << D.row(2) << std::endl << D.row(3) << std::endl << D.row(4) << std::endl << D.row(5) << std::endl;
671
672 //
673 // Put it all together
674 //
675 p_outMT = t_MT_new;
676
677 return p_outMT;
678}
679
680//=============================================================================================================
681
683 MNEForwardSolution forward,
684 const FiffCov &p_noise_cov,
685 float loose,
686 float depth,
687 bool fixed,
688 bool limit_depth_chs)
689{
690 bool is_fixed_ori = forward.isFixedOrient();
691 MNEInverseOperator p_MNEInverseOperator;
692
693 std::cout << "ToDo MNEInverseOperator::make_inverse_operator: do surf_ori check" << std::endl;
694
695 //Check parameters
696 if(fixed && loose > 0)
697 {
698 qWarning("Warning: When invoking make_inverse_operator with fixed = true, the loose parameter is ignored.\n");
699 loose = 0.0f;
700 }
701
702 if(is_fixed_ori && !fixed)
703 {
704 qWarning("Warning: Setting fixed parameter = true. Because the given forward operator has fixed orientation and can only be used to make a fixed-orientation inverse operator.\n");
705 fixed = true;
706 }
707
708 if(forward.source_ori == -1 && loose > 0)
709 {
710 qCritical("Error: Forward solution is not oriented in surface coordinates. loose parameter should be 0 not %f.\n", loose);
711 return p_MNEInverseOperator;
712 }
713
714 if(loose < 0 || loose > 1)
715 {
716 qWarning("Warning: Loose value should be in interval [0,1] not %f.\n", loose);
717 loose = loose > 1 ? 1 : 0;
718 printf("Setting loose to %f.\n", loose);
719 }
720
721 if(depth < 0 || depth > 1)
722 {
723 qWarning("Warning: Depth value should be in interval [0,1] not %f.\n", depth);
724 depth = depth > 1 ? 1 : 0;
725 printf("Setting depth to %f.\n", depth);
726 }
727
728 //
729 // 1. Read the bad channels
730 // 2. Read the necessary data from the forward solution matrix file
731 // 3. Load the projection data
732 // 4. Load the sensor noise covariance matrix and attach it to the forward
733 //
734 FiffInfo gain_info;
735 MatrixXd gain;
736 MatrixXd whitener;
737 qint32 n_nzero;
738 FiffCov p_outNoiseCov;
739 forward.prepare_forward(info, p_noise_cov, false, gain_info, gain, p_outNoiseCov, whitener, n_nzero);
740
741 //
742 // 5. Compose the depth weight matrix
743 //
744 FiffCov::SDPtr p_depth_prior;
745 MatrixXd patch_areas;
746 if(depth > 0)
747 {
748 std::cout << "ToDo: patch_areas" << std::endl;
749// patch_areas = forward.get('patch_areas', None)
750 p_depth_prior = FiffCov::SDPtr(new FiffCov(MNEForwardSolution::compute_depth_prior(gain, gain_info, is_fixed_ori, depth, 10.0, patch_areas, limit_depth_chs)));
751 }
752 else
753 {
754 p_depth_prior->data = MatrixXd::Ones(gain.cols(), gain.cols());
755 p_depth_prior->kind = FIFFV_MNE_DEPTH_PRIOR_COV;
756 p_depth_prior->diag = true;
757 p_depth_prior->dim = gain.cols();
758 p_depth_prior->nfree = 1;
759 }
760
761 // Deal with fixed orientation forward / inverse
762 if(fixed)
763 {
764 if(depth < 0 || depth > 1)
765 {
766 // Convert the depth prior into a fixed-orientation one
767 printf("\tToDo: Picked elements from a free-orientation depth-weighting prior into the fixed-orientation one.\n");
768 }
769 if(!is_fixed_ori)
770 {
771 // Convert to the fixed orientation forward solution now
772 qint32 count = 0;
773 for(qint32 i = 2; i < p_depth_prior->data.rows(); i+=3)
774 {
775 p_depth_prior->data.row(count) = p_depth_prior->data.row(i);
776 ++count;
777 }
778 p_depth_prior->data.conservativeResize(count, 1);
779
780// forward = deepcopy(forward)
781 forward.to_fixed_ori();
782 is_fixed_ori = forward.isFixedOrient();
783 forward.prepare_forward(info, p_outNoiseCov, false, gain_info, gain, p_outNoiseCov, whitener, n_nzero);
784 }
785 }
786 printf("\tComputing inverse operator with %lld channels.\n", gain_info.ch_names.size());
787
788 //
789 // 6. Compose the source covariance matrix
790 //
791 printf("\tCreating the source covariance matrix\n");
792 FiffCov::SDPtr p_source_cov = p_depth_prior;
793
794 // apply loose orientations
795 FiffCov::SDPtr p_orient_prior;
796 if(!is_fixed_ori)
797 {
798 p_orient_prior = FiffCov::SDPtr(new FiffCov(forward.compute_orient_prior(loose)));
799 p_source_cov->data.array() *= p_orient_prior->data.array();
800 }
801
802 // 7. Apply fMRI weighting (not done)
803
804 //
805 // 8. Apply the linear projection to the forward solution
806 // 9. Apply whitening to the forward computation matrix
807 //
808 printf("\tWhitening the forward solution.\n");
809 gain = whitener*gain;
810
811 // 10. Exclude the source space points within the labels (not done)
812
813 //
814 // 11. Do appropriate source weighting to the forward computation matrix
815 //
816
817 // Adjusting Source Covariance matrix to make trace of G*R*G' equal
818 // to number of sensors.
819 printf("\tAdjusting source covariance matrix.\n");
820 RowVectorXd source_std = p_source_cov->data.array().sqrt().transpose();
821
822 for(qint32 i = 0; i < gain.rows(); ++i)
823 gain.row(i) = gain.row(i).array() * source_std.array();
824
825 double trace_GRGT = (gain * gain.transpose()).trace();//pow(gain.norm(), 2);
826 double scaling_source_cov = (double)n_nzero / trace_GRGT;
827
828 p_source_cov->data.array() *= scaling_source_cov;
829
830 gain.array() *= sqrt(scaling_source_cov);
831
832 // now np.trace(np.dot(gain, gain.T)) == n_nzero
833 // logger.info(np.trace(np.dot(gain, gain.T)), n_nzero)
834
835 //
836 // 12. Decompose the combined matrix
837 //
838 printf("Computing SVD of whitened and weighted lead field matrix.\n");
839 JacobiSVD<MatrixXd> svd(gain, ComputeThinU | ComputeThinV);
840 std::cout << "ToDo Sorting Necessary?" << std::endl;
841 VectorXd p_sing = svd.singularValues();
842 MatrixXd t_U = svd.matrixU();
843 MNEMath::sort<double>(p_sing, t_U);
844 FiffNamedMatrix::SDPtr p_eigen_fields = FiffNamedMatrix::SDPtr(new FiffNamedMatrix( svd.matrixU().cols(),
845 svd.matrixU().rows(),
846 defaultQStringList,
847 gain_info.ch_names,
848 t_U.transpose() ));
849
850 p_sing = svd.singularValues();
851 MatrixXd t_V = svd.matrixV();
852 MNEMath::sort<double>(p_sing, t_V);
853 FiffNamedMatrix::SDPtr p_eigen_leads = FiffNamedMatrix::SDPtr(new FiffNamedMatrix( svd.matrixV().rows(),
854 svd.matrixV().cols(),
855 defaultQStringList,
856 defaultQStringList,
857 t_V ));
858 printf("\tlargest singular value = %f\n", p_sing.maxCoeff());
859 printf("\tscaling factor to adjust the trace = %f\n", trace_GRGT);
860
861 qint32 p_nave = 1.0;
862
863 // Handle methods
864 bool has_meg = false;
865 bool has_eeg = false;
866
867 RowVectorXd ch_idx(info.chs.size());
868 qint32 count = 0;
869 for(qint32 i = 0; i < info.chs.size(); ++i)
870 {
871 if(gain_info.ch_names.contains(info.chs[i].ch_name))
872 {
873 ch_idx[count] = i;
874 ++count;
875 }
876 }
877 ch_idx.conservativeResize(count);
878
879 for(qint32 i = 0; i < ch_idx.size(); ++i)
880 {
881 QString ch_type = info.channel_type(ch_idx[i]);
882 if (ch_type == "eeg")
883 has_eeg = true;
884 if ((ch_type == "mag") || (ch_type == "grad"))
885 has_meg = true;
886 }
887
888 qint32 p_iMethods;
889
890 if(has_eeg && has_meg)
891 p_iMethods = FIFFV_MNE_MEG_EEG;
892 else if(has_meg)
893 p_iMethods = FIFFV_MNE_MEG;
894 else
895 p_iMethods = FIFFV_MNE_EEG;
896
897 // We set this for consistency with mne C code written inverses
898 if(depth == 0)
899 p_depth_prior = FiffCov::SDPtr();
900
901 p_MNEInverseOperator.eigen_fields = p_eigen_fields;
902 p_MNEInverseOperator.eigen_leads = p_eigen_leads;
903 p_MNEInverseOperator.sing = p_sing;
904 p_MNEInverseOperator.nave = p_nave;
905 p_MNEInverseOperator.depth_prior = p_depth_prior;
906 p_MNEInverseOperator.source_cov = p_source_cov;
907 p_MNEInverseOperator.noise_cov = FiffCov::SDPtr(new FiffCov(p_outNoiseCov));
908 p_MNEInverseOperator.orient_prior = p_orient_prior;
909 p_MNEInverseOperator.projs = info.projs;
910 p_MNEInverseOperator.eigen_leads_weighted = false;
911 p_MNEInverseOperator.source_ori = forward.source_ori;
912 p_MNEInverseOperator.mri_head_t = forward.mri_head_t;
913 p_MNEInverseOperator.methods = p_iMethods;
914 p_MNEInverseOperator.nsource = forward.nsource;
915 p_MNEInverseOperator.coord_frame = forward.coord_frame;
916 p_MNEInverseOperator.source_nn = forward.source_nn;
917 p_MNEInverseOperator.src = forward.src;
918 p_MNEInverseOperator.info = forward.info;
919 p_MNEInverseOperator.info.bads = info.bads;
920
921 return p_MNEInverseOperator;
922}
923
924//=============================================================================================================
925
926MNEInverseOperator MNEInverseOperator::prepare_inverse_operator(qint32 nave ,float lambda2, bool dSPM, bool sLORETA) const
927{
928 if(nave <= 0)
929 {
930 printf("The number of averages should be positive\n");
931 return MNEInverseOperator();
932 }
933 printf("Preparing the inverse operator for use...\n");
934 MNEInverseOperator inv(*this);
935 //
936 // Scale some of the stuff
937 //
938 float scale = ((float)inv.nave)/((float)nave);
939 inv.noise_cov->data *= scale;
940 inv.noise_cov->eig *= scale;
941 inv.source_cov->data *= scale;
942 //
943 if (inv.eigen_leads_weighted)
944 inv.eigen_leads->data *= sqrt(scale);
945 //
946 printf("\tScaled noise and source covariance from nave = %d to nave = %d\n",inv.nave,nave);
947 inv.nave = nave;
948 //
949 // Create the diagonal matrix for computing the regularized inverse
950 //
951 VectorXd tmp = inv.sing.cwiseProduct(inv.sing) + VectorXd::Constant(inv.sing.size(), lambda2);
952// if(inv.reginv)
953// delete inv.reginv;
954 inv.reginv = VectorXd(inv.sing.cwiseQuotient(tmp));
955 printf("\tCreated the regularized inverter\n");
956 //
957 // Create the projection operator
958 //
959
960 qint32 ncomp = FiffProj::make_projector(inv.projs, inv.noise_cov->names, inv.proj);
961 if (ncomp > 0)
962 printf("\tCreated an SSP operator (subspace dimension = %d)\n",ncomp);
963
964 //
965 // Create the whitener
966 //
967// if(inv.whitener)
968// delete inv.whitener;
969 inv.whitener = MatrixXd::Zero(inv.noise_cov->dim, inv.noise_cov->dim);
970
971 qint32 nnzero, k;
972 if (inv.noise_cov->diag == 0)
973 {
974 //
975 // Omit the zeroes due to projection
976 //
977 nnzero = 0;
978
979 for (k = ncomp; k < inv.noise_cov->dim; ++k)
980 {
981 if (inv.noise_cov->eig[k] > 0)
982 {
983 inv.whitener(k,k) = 1.0/sqrt(inv.noise_cov->eig[k]);
984 ++nnzero;
985 }
986 }
987 //
988 // Rows of eigvec are the eigenvectors
989 //
990 inv.whitener *= inv.noise_cov->eigvec;
991 printf("\tCreated the whitener using a full noise covariance matrix (%d small eigenvalues omitted)\n", inv.noise_cov->dim - nnzero);
992 }
993 else
994 {
995 //
996 // No need to omit the zeroes due to projection
997 //
998 for (k = 0; k < inv.noise_cov->dim; ++k)
999 inv.whitener(k,k) = 1.0/sqrt(inv.noise_cov->data(k,0));
1000
1001 printf("\tCreated the whitener using a diagonal noise covariance matrix (%d small eigenvalues discarded)\n",ncomp);
1002 }
1003 //
1004 // Finally, compute the noise-normalization factors
1005 //
1006 if (dSPM || sLORETA)
1007 {
1008 VectorXd noise_norm = VectorXd::Zero(inv.eigen_leads->nrow);
1009 VectorXd noise_weight;
1010 if (dSPM)
1011 {
1012 printf("\tComputing noise-normalization factors (dSPM)...");
1013 noise_weight = VectorXd(inv.reginv);
1014 }
1015 else
1016 {
1017 printf("\tComputing noise-normalization factors (sLORETA)...");
1018 VectorXd tmp = (VectorXd::Constant(inv.sing.size(), 1) + inv.sing.cwiseProduct(inv.sing)/lambda2);
1019 noise_weight = inv.reginv.cwiseProduct(tmp.cwiseSqrt());
1020 }
1021 VectorXd one;
1022 if (inv.eigen_leads_weighted)
1023 {
1024 for (k = 0; k < inv.eigen_leads->nrow; ++k)
1025 {
1026 one = inv.eigen_leads->data.block(k,0,1,inv.eigen_leads->data.cols()).cwiseProduct(noise_weight);
1027 noise_norm[k] = sqrt(one.dot(one));
1028 }
1029 }
1030 else
1031 {
1032// qDebug() << 32;
1033 double c;
1034 for (k = 0; k < inv.eigen_leads->nrow; ++k)
1035 {
1036// qDebug() << 321;
1037 c = sqrt(inv.source_cov->data(k,0));
1038// qDebug() << 322;
1039// qDebug() << "inv.eigen_leads->data" << inv.eigen_leads->data.rows() << "x" << inv.eigen_leads->data.cols();
1040// qDebug() << "noise_weight" << noise_weight.rows() << "x" << noise_weight.cols();
1041 one = c*(inv.eigen_leads->data.row(k).transpose()).cwiseProduct(noise_weight);//ToDo eigenleads data -> pointer
1042 noise_norm[k] = sqrt(one.dot(one));
1043// qDebug() << 324;
1044 }
1045 }
1046
1047// qDebug() << 4;
1048
1049 //
1050 // Compute the final result
1051 //
1052 VectorXd noise_norm_new;
1053 if (inv.source_ori == FIFFV_MNE_FREE_ORI)
1054 {
1055 //
1056 // The three-component case is a little bit more involved
1057 // The variances at three consequtive entries must be squeared and
1058 // added together
1059 //
1060 // Even in this case return only one noise-normalization factor
1061 // per source location
1062 //
1063 VectorXd* t = MNEMath::combine_xyz(noise_norm.transpose());
1064 noise_norm_new = t->cwiseSqrt();//double otherwise values are getting too small
1065 delete t;
1066 //
1067 // This would replicate the same value on three consequtive
1068 // entries
1069 //
1070 // noise_norm = kron(sqrt(mne_combine_xyz(noise_norm)),ones(3,1));
1071 }
1072 VectorXd vOnes = VectorXd::Ones(noise_norm_new.size());
1073 VectorXd tmp = vOnes.cwiseQuotient(noise_norm_new.cwiseAbs());
1074// if(inv.noisenorm)
1075// delete inv.noisenorm;
1076
1077 typedef Eigen::Triplet<double> T;
1078 std::vector<T> tripletList;
1079 tripletList.reserve(noise_norm_new.size());
1080 for(qint32 i = 0; i < noise_norm_new.size(); ++i)
1081 tripletList.push_back(T(i, i, tmp[i]));
1082
1083 inv.noisenorm = SparseMatrix<double>(noise_norm_new.size(),noise_norm_new.size());
1084 inv.noisenorm.setFromTriplets(tripletList.begin(), tripletList.end());
1085
1086 printf("[done]\n");
1087 }
1088 else
1089 {
1090// if(inv.noisenorm)
1091// delete inv.noisenorm;
1092 inv.noisenorm = SparseMatrix<double>();
1093 }
1094
1095 return inv;
1096}
1097
1098//=============================================================================================================
1099
1101{
1102 //
1103 // Open the file, create directory
1104 //
1105 FiffStream::SPtr t_pStream(new FiffStream(&p_IODevice));
1106 printf("Reading inverse operator decomposition from %s...\n",t_pStream->streamName().toUtf8().constData());
1107
1108 if(!t_pStream->open())
1109 return false;
1110 //
1111 // Find all inverse operators
1112 //
1113 QList <FiffDirNode::SPtr> invs_list = t_pStream->dirtree()->dir_tree_find(FIFFB_MNE_INVERSE_SOLUTION);
1114 if ( invs_list.size()== 0)
1115 {
1116 printf("No inverse solutions in %s\n", t_pStream->streamName().toUtf8().constData());
1117 return false;
1118 }
1119 FiffDirNode::SPtr invs = invs_list[0];
1120 //
1121 // Parent MRI data
1122 //
1123 QList <FiffDirNode::SPtr> parent_mri = t_pStream->dirtree()->dir_tree_find(FIFFB_MNE_PARENT_MRI_FILE);
1124 if (parent_mri.size() == 0)
1125 {
1126 printf("No parent MRI information in %s", t_pStream->streamName().toUtf8().constData());
1127 return false;
1128 }
1129 printf("\tReading inverse operator info...");
1130 //
1131 // Methods and source orientations
1132 //
1133 FiffTag::SPtr t_pTag;
1134 if (!invs->find_tag(t_pStream, FIFF_MNE_INCLUDED_METHODS, t_pTag))
1135 {
1136 printf("Modalities not found\n");
1137 return false;
1138 }
1139
1140 inv = MNEInverseOperator();
1141 inv.methods = *t_pTag->toInt();
1142 //
1143 if (!invs->find_tag(t_pStream, FIFF_MNE_SOURCE_ORIENTATION, t_pTag))
1144 {
1145 printf("Source orientation constraints not found\n");
1146 return false;
1147 }
1148 inv.source_ori = *t_pTag->toInt();
1149 //
1150 if (!invs->find_tag(t_pStream, FIFF_MNE_SOURCE_SPACE_NPOINTS, t_pTag))
1151 {
1152 printf("Number of sources not found\n");
1153 return false;
1154 }
1155 inv.nsource = *t_pTag->toInt();
1156 inv.nchan = 0;
1157 //
1158 // Coordinate frame
1159 //
1160 if (!invs->find_tag(t_pStream, FIFF_MNE_COORD_FRAME, t_pTag))
1161 {
1162 printf("Coordinate frame tag not found\n");
1163 return false;
1164 }
1165 inv.coord_frame = *t_pTag->toInt();
1166 //
1167 // The actual source orientation vectors
1168 //
1169 if (!invs->find_tag(t_pStream, FIFF_MNE_INVERSE_SOURCE_ORIENTATIONS, t_pTag))
1170 {
1171 printf("Source orientation information not found\n");
1172 return false;
1173 }
1174
1175// if(inv.source_nn)
1176// delete inv.source_nn;
1177 inv.source_nn = t_pTag->toFloatMatrix();
1178 inv.source_nn.transposeInPlace();
1179
1180 printf("[done]\n");
1181 //
1182 // The SVD decomposition...
1183 //
1184 printf("\tReading inverse operator decomposition...");
1185 if (!invs->find_tag(t_pStream, FIFF_MNE_INVERSE_SING, t_pTag))
1186 {
1187 printf("Singular values not found\n");
1188 return false;
1189 }
1190
1191// if(inv.sing)
1192// delete inv.sing;
1193 inv.sing = Map<VectorXf>(t_pTag->toFloat(), t_pTag->size()/4).cast<double>();
1194 inv.nchan = inv.sing.rows();
1195 //
1196 // The eigenleads and eigenfields
1197 //
1198 inv.eigen_leads_weighted = false;
1199 if(!t_pStream->read_named_matrix(invs, FIFF_MNE_INVERSE_LEADS, *inv.eigen_leads.data()))
1200 {
1201 inv.eigen_leads_weighted = true;
1202 if(!t_pStream->read_named_matrix(invs, FIFF_MNE_INVERSE_LEADS_WEIGHTED, *inv.eigen_leads.data()))
1203 {
1204 printf("Error reading eigenleads named matrix.\n");
1205 return false;
1206 }
1207 }
1208 //
1209 // Having the eigenleads as columns is better for the inverse calculations
1210 //
1211 inv.eigen_leads->transpose_named_matrix();
1212
1213 if(!t_pStream->read_named_matrix(invs, FIFF_MNE_INVERSE_FIELDS, *inv.eigen_fields.data()))
1214 {
1215 printf("Error reading eigenfields named matrix.\n");
1216 return false;
1217 }
1218 printf("[done]\n");
1219 //
1220 // Read the covariance matrices
1221 //
1222 if(t_pStream->read_cov(invs, FIFFV_MNE_NOISE_COV, *inv.noise_cov.data()))
1223 {
1224 printf("\tNoise covariance matrix read.\n");
1225 }
1226 else
1227 {
1228 printf("\tError: Not able to read noise covariance matrix.\n");
1229 return false;
1230 }
1231
1232 if(t_pStream->read_cov(invs, FIFFV_MNE_SOURCE_COV, *inv.source_cov.data()))
1233 {
1234 printf("\tSource covariance matrix read.\n");
1235 }
1236 else
1237 {
1238 printf("\tError: Not able to read source covariance matrix.\n");
1239 return false;
1240 }
1241 //
1242 // Read the various priors
1243 //
1244 if(t_pStream->read_cov(invs, FIFFV_MNE_ORIENT_PRIOR_COV, *inv.orient_prior.data()))
1245 {
1246 printf("\tOrientation priors read.\n");
1247 }
1248 else
1249 inv.orient_prior->clear();
1250
1251 if(t_pStream->read_cov(invs, FIFFV_MNE_DEPTH_PRIOR_COV, *inv.depth_prior.data()))
1252 {
1253 printf("\tDepth priors read.\n");
1254 }
1255 else
1256 {
1257 inv.depth_prior->clear();
1258 }
1259 if(t_pStream->read_cov(invs, FIFFV_MNE_FMRI_PRIOR_COV, *inv.fmri_prior.data()))
1260 {
1261 printf("\tfMRI priors read.\n");
1262 }
1263 else
1264 {
1265 inv.fmri_prior->clear();
1266 }
1267 //
1268 // Read the source spaces
1269 //
1270 if(!MNESourceSpace::readFromStream(t_pStream, false, inv.src))
1271 {
1272 printf("\tError: Could not read the source spaces.\n");
1273 return false;
1274 }
1275 for (qint32 k = 0; k < inv.src.size(); ++k)
1277 //
1278 // Get the MRI <-> head coordinate transformation
1279 //
1280 FiffCoordTrans mri_head_t;// = NULL;
1281 if (!parent_mri[0]->find_tag(t_pStream, FIFF_COORD_TRANS, t_pTag))
1282 {
1283 printf("MRI/head coordinate transformation not found\n");
1284 return false;
1285 }
1286 else
1287 {
1288 mri_head_t = t_pTag->toCoordTrans();
1289 if (mri_head_t.from != FIFFV_COORD_MRI || mri_head_t.to != FIFFV_COORD_HEAD)
1290 {
1292 if (mri_head_t.from != FIFFV_COORD_MRI || mri_head_t.to != FIFFV_COORD_HEAD)
1293 {
1294 printf("MRI/head coordinate transformation not found");
1295// if(mri_head_t)
1296// delete mri_head_t;
1297 return false;
1298 }
1299 }
1300 }
1301 inv.mri_head_t = mri_head_t;
1302
1303 //
1304 // get parent MEG info
1305 //
1306 t_pStream->read_meas_info_base(t_pStream->dirtree(), inv.info);
1307
1308 //
1309 // Transform the source spaces to the correct coordinate frame
1310 // if necessary
1311 //
1312 if (inv.coord_frame != FIFFV_COORD_MRI && inv.coord_frame != FIFFV_COORD_HEAD)
1313 printf("Only inverse solutions computed in MRI or head coordinates are acceptable");
1314 //
1315 // Number of averages is initially one
1316 //
1317 inv.nave = 1;
1318 //
1319 // We also need the SSP operator
1320 //
1321 inv.projs = t_pStream->read_proj(t_pStream->dirtree());
1322 //
1323 // Some empty fields to be filled in later
1324 //
1325// inv.proj = []; % This is the projector to apply to the data
1326// inv.whitener = []; % This whitens the data
1327// inv.reginv = []; % This the diagonal matrix implementing
1328// % regularization and the inverse
1329// inv.noisenorm = []; % These are the noise-normalization factors
1330 //
1332 {
1333 printf("Could not transform source space.\n");
1334 }
1335 printf("\tSource spaces transformed to the inverse solution coordinate frame\n");
1336 //
1337 // Done!
1338 //
1339
1340 return true;
1341}
1342
1343//=============================================================================================================
1344
1345void MNEInverseOperator::write(QIODevice &p_IODevice)
1346{
1347 //
1348 // Open the file, create directory
1349 //
1350
1351 // Create the file and save the essentials
1352 FiffStream::SPtr t_pStream = FiffStream::start_file(p_IODevice);
1353 printf("Write inverse operator decomposition in %s...", t_pStream->streamName().toUtf8().constData());
1354 this->writeToStream(t_pStream.data());
1355 t_pStream->end_file();
1356}
1357
1358//=============================================================================================================
1359
1361{
1362 p_pStream->start_block(FIFFB_MNE_INVERSE_SOLUTION);
1363
1364 printf("\tWriting inverse operator info...\n");
1365
1366 p_pStream->write_int(FIFF_MNE_INCLUDED_METHODS, &this->methods);
1369 p_pStream->write_int(FIFF_MNE_COORD_FRAME, &this->coord_frame);
1371 VectorXf tmp_sing = this->sing.cast<float>();
1372 p_pStream->write_float(FIFF_MNE_INVERSE_SING, tmp_sing.data(), tmp_sing.size());
1373
1374 //
1375 // The eigenleads and eigenfields
1376 //
1377 if(this->eigen_leads_weighted)
1378 {
1379 FiffNamedMatrix tmpMatrix(*this->eigen_leads.data());
1380 tmpMatrix.transpose_named_matrix();
1382 }
1383 else
1384 {
1385 FiffNamedMatrix tmpMatrix(*this->eigen_leads.data());
1386 tmpMatrix.transpose_named_matrix();
1387 p_pStream->write_named_matrix(FIFF_MNE_INVERSE_LEADS, tmpMatrix);
1388 }
1389
1390 p_pStream->write_named_matrix(FIFF_MNE_INVERSE_FIELDS, *this->eigen_fields.data());
1391 printf("\t[done]\n");
1392 //
1393 // write the covariance matrices
1394 //
1395 printf("\tWriting noise covariance matrix.");
1396 p_pStream->write_cov(*this->noise_cov.data());
1397
1398 printf("\tWriting source covariance matrix.\n");
1399 p_pStream->write_cov(*this->source_cov.data());
1400 //
1401 // write the various priors
1402 //
1403 printf("\tWriting orientation priors.\n");
1404 if(!this->orient_prior->isEmpty())
1405 p_pStream->write_cov(*this->orient_prior.data());
1406 if(!this->depth_prior->isEmpty())
1407 p_pStream->write_cov(*this->depth_prior.data());
1408 if(!this->fmri_prior->isEmpty())
1409 p_pStream->write_cov(*this->fmri_prior.data());
1410
1411 //
1412 // Parent MRI data
1413 //
1414 p_pStream->start_block(FIFFB_MNE_PARENT_MRI_FILE);
1415 // write the MRI <-> head coordinate transformation
1416 p_pStream->write_coord_trans(this->mri_head_t);
1417 p_pStream->end_block(FIFFB_MNE_PARENT_MRI_FILE);
1418
1419 //
1420 // Parent MEG measurement info
1421 //
1422 p_pStream->write_info_base(this->info);
1423
1424 //
1425 // Write the source spaces
1426 //
1427 if(!src.isEmpty())
1428 this->src.writeToStream(p_pStream);
1429
1430 //
1431 // We also need the SSP operator
1432 //
1433 p_pStream->write_proj(this->projs);
1434 //
1435 // Done!
1436 //
1437 p_pStream->end_block(FIFFB_MNE_INVERSE_SOLUTION);
1438}
#define FIFF_MNE_INVERSE_FIELDS
#define FIFF_MNE_INVERSE_LEADS
#define FIFF_MNE_INVERSE_SOURCE_ORIENTATIONS
#define FIFF_MNE_COORD_FRAME
#define FIFF_MNE_SOURCE_ORIENTATION
#define FIFFV_MNE_NOISE_COV
#define FIFF_MNE_INVERSE_LEADS_WEIGHTED
#define FIFF_MNE_SOURCE_SPACE_NPOINTS
#define FIFF_MNE_INVERSE_SING
#define FIFFV_MNE_ORIENT_PRIOR_COV
#define FIFFV_MNE_DEPTH_PRIOR_COV
int k
Definition fiff_tag.cpp:324
#define FIFF_COORD_TRANS
Definition fiff_file.h:475
Label class declaration.
Coordinate transformation description.
covariance data
Definition fiff_cov.h:78
QSharedDataPointer< FiffCov > SDPtr
Definition fiff_cov.h:82
QSharedPointer< FiffDirNode > SPtr
FIFF measurement file information.
Definition fiff_info.h:85
QString channel_type(qint32 idx) const
QList< FiffChInfo > chs
QSharedDataPointer< FiffNamedMatrix > SDPtr
static fiff_int_t make_projector(const QList< FiffProj > &projs, const QStringList &ch_names, Eigen::MatrixXd &proj, const QStringList &bads=defaultQStringList, Eigen::MatrixXd &U=defaultMatrixXd)
FIFF File I/O routines.
fiff_long_t write_cov(const FiffCov &p_FiffCov)
fiff_long_t start_block(fiff_int_t kind)
fiff_long_t write_float_matrix(fiff_int_t kind, const Eigen::MatrixXf &mat)
fiff_long_t write_proj(const QList< FiffProj > &projs)
fiff_long_t write_int(fiff_int_t kind, const fiff_int_t *data, fiff_int_t nel=1, fiff_int_t next=FIFFV_NEXT_SEQ)
fiff_long_t write_float(fiff_int_t kind, const float *data, fiff_int_t nel=1)
fiff_long_t write_coord_trans(const FiffCoordTrans &trans)
fiff_long_t write_named_matrix(fiff_int_t kind, const FiffNamedMatrix &mat)
static FiffStream::SPtr start_file(QIODevice &p_IODevice)
fiff_long_t write_info_base(const FiffInfoBase &p_FiffInfoBase)
fiff_long_t end_block(fiff_int_t kind, fiff_int_t next=FIFFV_NEXT_SEQ)
QSharedPointer< FiffStream > SPtr
QSharedPointer< FiffTag > SPtr
Definition fiff_tag.h:152
Annotation set.
Vertices label based lookup table.
Definition colortable.h:68
Eigen::VectorXi getLabelIds() const
Definition colortable.h:120
QStringList struct_names
Definition colortable.h:112
Freesurfer/MNE label.
Definition label.h:81
bool isEmpty() const
Definition label.h:184
cluster information
static FIFFLIB::FiffCov compute_depth_prior(const Eigen::MatrixXd &Gain, const FIFFLIB::FiffInfo &gain_info, bool is_fixed_ori, double exp=0.8, double limit=10.0, const Eigen::MatrixXd &patch_areas=FIFFLIB::defaultConstMatrixXd, bool limit_depth_chs=false)
void prepare_forward(const FIFFLIB::FiffInfo &p_info, const FIFFLIB::FiffCov &p_noise_cov, bool p_pca, FIFFLIB::FiffInfo &p_outFwdInfo, Eigen::MatrixXd &gain, FIFFLIB::FiffCov &p_outNoiseCov, Eigen::MatrixXd &p_outWhitener, qint32 &p_outNumNonZero) const
FIFFLIB::FiffCoordTrans mri_head_t
FIFFLIB::FiffCov compute_orient_prior(float loose=0.2)
Eigen::MatrixXd matRoiMTOrig
Eigen::MatrixXd matRoiMT
FIFFLIB::FiffCov::SDPtr fmri_prior
static MNEInverseOperator make_inverse_operator(const FIFFLIB::FiffInfo &info, MNEForwardSolution forward, const FIFFLIB::FiffCov &p_noise_cov, float loose=0.2f, float depth=0.8f, bool fixed=false, bool limit_depth_chs=true)
Eigen::MatrixXd cluster_kernel(const FSLIB::AnnotationSet &p_AnnotationSet, qint32 p_iClusterSize, Eigen::MatrixXd &p_D, QString p_sMethod="cityblock") const
QList< FIFFLIB::FiffProj > projs
Eigen::SparseMatrix< double > noisenorm
FIFFLIB::FiffCov::SDPtr orient_prior
bool assemble_kernel(const FSLIB::Label &label, QString method, bool pick_normal, Eigen::MatrixXd &K, Eigen::SparseMatrix< double > &noise_norm, QList< Eigen::VectorXi > &vertno)
FIFFLIB::FiffNamedMatrix::SDPtr eigen_leads
bool check_ch_names(const FIFFLIB::FiffInfo &info) const
FIFFLIB::FiffCoordTrans mri_head_t
MNEInverseOperator prepare_inverse_operator(qint32 nave, float lambda2, bool dSPM, bool sLORETA=false) const
FIFFLIB::FiffCov::SDPtr depth_prior
void write(QIODevice &p_IODevice)
void writeToStream(FIFFLIB::FiffStream *p_pStream)
FIFFLIB::FiffCov::SDPtr noise_cov
FIFFLIB::FiffCov::SDPtr source_cov
static bool read_inverse_operator(QIODevice &p_IODevice, MNEInverseOperator &inv)
FIFFLIB::FiffNamedMatrix::SDPtr eigen_fields
QList< Eigen::VectorXi > get_vertno() const
static qint32 find_source_space_hemi(MNEHemisphere &p_Hemisphere)
QList< Eigen::VectorXi > label_src_vertno_sel(const FSLIB::Label &p_label, Eigen::VectorXi &src_sel) const
void writeToStream(FIFFLIB::FiffStream *p_pStream)
static bool readFromStream(FIFFLIB::FiffStream::SPtr &p_pStream, bool add_geom, MNESourceSpace &p_SourceSpace)
bool transform_source_space_to(FIFFLIB::fiff_int_t dest, FIFFLIB::FiffCoordTrans &trans)
static Eigen::VectorXi intersect(const Eigen::VectorXi &v1, const Eigen::VectorXi &v2, Eigen::VectorXi &idx_sel)
Definition mnemath.cpp:194
static Eigen::VectorXd * combine_xyz(const Eigen::VectorXd &vec)
Definition mnemath.cpp:81
MNEInverseOperator class declaration.