MNE-CPP  0.1.9
A Framework for Electrophysiology
mne_inverse_operator.cpp
Go to the documentation of this file.
1 //=============================================================================================================
38 //=============================================================================================================
39 // INCLUDES
40 //=============================================================================================================
41 
42 #include "mne_inverse_operator.h"
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 
64 using namespace UTILSLIB;
65 using namespace MNELIB;
66 using namespace FIFFLIB;
67 using namespace FSLIB;
68 using namespace Eigen;
69 
70 //=============================================================================================================
71 // DEFINE MEMBER METHODS
72 //=============================================================================================================
73 
74 MNEInverseOperator::MNEInverseOperator()
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 
153 {
154 }
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 
352 MatrixXd 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 
926 MNEInverseOperator 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 
1345 void 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);
1367  p_pStream->write_int(FIFF_MNE_SOURCE_ORIENTATION, &this->source_ori);
1368  p_pStream->write_int(FIFF_MNE_SOURCE_SPACE_NPOINTS, &this->nsource);
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();
1381  p_pStream->write_named_matrix(FIFF_MNE_INVERSE_LEADS_WEIGHTED, tmpMatrix);
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 }
FSLIB::Colortable::struct_names
QStringList struct_names
Definition: colortable.h:112
FIFFV_MNE_NOISE_COV
#define FIFFV_MNE_NOISE_COV
Definition: fiff_constants.h:448
MNELIB::MNEInverseOperator::prepare_inverse_operator
MNEInverseOperator prepare_inverse_operator(qint32 nave, float lambda2, bool dSPM, bool sLORETA=false) const
Definition: mne_inverse_operator.cpp:926
MNELIB::MNEForwardSolution::compute_depth_prior
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)
Definition: mne_forwardsolution.cpp:807
FIFFLIB::FiffStream::end_block
fiff_long_t end_block(fiff_int_t kind, fiff_int_t next=FIFFV_NEXT_SEQ)
Definition: fiff_stream.cpp:170
FIFFLIB::FiffStream::write_float_matrix
fiff_long_t write_float_matrix(fiff_int_t kind, const Eigen::MatrixXf &mat)
Definition: fiff_stream.cpp:2647
MNELIB::MNEInverseOperator::writeToStream
void writeToStream(FIFFLIB::FiffStream *p_pStream)
Definition: mne_inverse_operator.cpp:1360
FIFFLIB::FiffNamedMatrix::transpose_named_matrix
void transpose_named_matrix()
Definition: fiff_named_matrix.cpp:96
MNELIB::RegionMT::matRoiMTOrig
Eigen::MatrixXd matRoiMTOrig
Definition: mne_inverse_operator.h:106
FIFFLIB::FiffStream::write_info_base
fiff_long_t write_info_base(const FiffInfoBase &p_FiffInfoBase)
Definition: fiff_stream.cpp:2910
MNELIB::MNEInverseOperator::nave
FIFFLIB::fiff_int_t nave
Definition: mne_inverse_operator.h:374
FIFFLIB::FiffStream::SPtr
QSharedPointer< FiffStream > SPtr
Definition: fiff_stream.h:107
FIFFLIB::FiffInfo
FIFF measurement file information.
Definition: fiff_info.h:84
MNELIB::MNEInverseOperator::info
FIFFLIB::FiffInfoBase info
Definition: mne_inverse_operator.h:356
MNELIB::MNEForwardSolution::to_fixed_ori
void to_fixed_ori()
Definition: mne_forwardsolution.cpp:1817
MNELIB::MNESourceSpace::writeToStream
void writeToStream(FIFFLIB::FiffStream *p_pStream)
Definition: mne_sourcespace.cpp:761
MNELIB::MNEInverseOperator::eigen_fields
FIFFLIB::FiffNamedMatrix::SDPtr eigen_fields
Definition: mne_inverse_operator.h:366
MNELIB::MNEClusterInfo
cluster information
Definition: mne_cluster_info.h:72
FIFFLIB::FiffDirNode::SPtr
QSharedPointer< FiffDirNode > SPtr
Definition: fiff_dir_node.h:76
MNELIB::MNESourceSpace::label_src_vertno_sel
QList< Eigen::VectorXi > label_src_vertno_sel(const FSLIB::Label &p_label, Eigen::VectorXi &src_sel) const
Definition: mne_sourcespace.cpp:104
FSLIB::AnnotationSet
Annotation set.
Definition: annotationset.h:80
MNELIB::MNEInverseOperator::projs
QList< FIFFLIB::FiffProj > projs
Definition: mne_inverse_operator.h:375
MNELIB::MNEForwardSolution
Forward operator.
Definition: mne_forwardsolution.h:170
MNELIB::MNEForwardSolution::source_ori
FIFFLIB::fiff_int_t source_ori
Definition: mne_forwardsolution.h:521
MNELIB::MNEForwardSolution::prepare_forward
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
Definition: mne_forwardsolution.cpp:1093
FIFFLIB::FiffStream::write_cov
fiff_long_t write_cov(const FiffCov &p_FiffCov)
Definition: fiff_stream.cpp:2389
MNELIB::MNEInverseOperator::mri_head_t
FIFFLIB::FiffCoordTrans mri_head_t
Definition: mne_inverse_operator.h:373
MNELIB::MNEInverseOperator::src
MNESourceSpace src
Definition: mne_inverse_operator.h:372
MNELIB::MNEInverseOperator::read_inverse_operator
static bool read_inverse_operator(QIODevice &p_IODevice, MNEInverseOperator &inv)
Definition: mne_inverse_operator.cpp:1100
k
int k
Definition: fiff_tag.cpp:322
MNELIB::MNEInverseOperator::check_ch_names
bool check_ch_names(const FIFFLIB::FiffInfo &info) const
Definition: mne_inverse_operator.cpp:307
MNELIB::MNEInverseOperator::~MNEInverseOperator
~MNEInverseOperator()
Definition: mne_inverse_operator.cpp:152
FIFFLIB::FiffInfoBase::bads
QStringList bads
Definition: fiff_info_base.h:220
MNELIB::MNEInverseOperator::nsource
FIFFLIB::fiff_int_t nsource
Definition: mne_inverse_operator.h:359
MNELIB::MNEInverseOperator::orient_prior
FIFFLIB::FiffCov::SDPtr orient_prior
Definition: mne_inverse_operator.h:369
MNELIB::MNEInverseOperator::make_inverse_operator
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)
Definition: mne_inverse_operator.cpp:682
FSLIB::Label
Freesurfer/MNE label.
Definition: label.h:80
MNELIB::MNEInverseOperator::MNEInverseOperator
MNEInverseOperator()
Definition: mne_inverse_operator.cpp:74
MNELIB::MNESourceSpace::transform_source_space_to
bool transform_source_space_to(FIFFLIB::fiff_int_t dest, FIFFLIB::FiffCoordTrans &trans)
Definition: mne_sourcespace.cpp:330
MNELIB::MNEForwardSolution::nsource
FIFFLIB::fiff_int_t nsource
Definition: mne_forwardsolution.h:524
MNELIB::MNEInverseOperator::fmri_prior
FIFFLIB::FiffCov::SDPtr fmri_prior
Definition: mne_inverse_operator.h:371
MNELIB::MNEInverseOperator::eigen_leads
FIFFLIB::FiffNamedMatrix::SDPtr eigen_leads
Definition: mne_inverse_operator.h:365
FIFFLIB::FiffNamedMatrix::SDPtr
QSharedDataPointer< FiffNamedMatrix > SDPtr
Definition: fiff_named_matrix.h:81
FIFFLIB::FiffStream::write_proj
fiff_long_t write_proj(const QList< FiffProj > &projs)
Definition: fiff_stream.cpp:3058
FIFF_MNE_COORD_FRAME
#define FIFF_MNE_COORD_FRAME
Definition: fiff_constants.h:331
MNELIB::RegionMT::matRoiMT
Eigen::MatrixXd matRoiMT
Definition: mne_inverse_operator.h:105
MNELIB::MNEInverseOperator::assemble_kernel
bool assemble_kernel(const FSLIB::Label &label, QString method, bool pick_normal, Eigen::MatrixXd &K, Eigen::SparseMatrix< double > &noise_norm, QList< Eigen::VectorXi > &vertno)
Definition: mne_inverse_operator.cpp:158
MNELIB::MNEForwardSolution::isFixedOrient
bool isFixedOrient() const
Definition: mne_forwardsolution.h:552
mne_inverse_operator.h
MNEInverseOperator class declaration.
MNELIB::MNEForwardSolution::coord_frame
FIFFLIB::fiff_int_t coord_frame
Definition: mne_forwardsolution.h:523
MNELIB::MNEInverseOperator::eigen_leads_weighted
bool eigen_leads_weighted
Definition: mne_inverse_operator.h:364
label.h
Label class declaration.
FIFF_COORD_TRANS
#define FIFF_COORD_TRANS
Definition: fiff_file.h:475
FIFFLIB::FiffCov::SDPtr
QSharedDataPointer< FiffCov > SDPtr
Definition: fiff_cov.h:82
MNELIB::MNESourceSpace::find_source_space_hemi
static qint32 find_source_space_hemi(MNEHemisphere &p_Hemisphere)
Definition: mne_sourcespace.cpp:315
MNELIB::MNEInverseOperator::depth_prior
FIFFLIB::FiffCov::SDPtr depth_prior
Definition: mne_inverse_operator.h:370
MNELIB::MNEInverseOperator::source_nn
Eigen::MatrixXf source_nn
Definition: mne_inverse_operator.h:362
MNELIB::MNEForwardSolution::compute_orient_prior
FIFFLIB::FiffCov compute_orient_prior(float loose=0.2)
Definition: mne_forwardsolution.cpp:916
MNELIB::MNEInverseOperator::sing
Eigen::VectorXd sing
Definition: mne_inverse_operator.h:363
FIFFLIB::FiffTag::SPtr
QSharedPointer< FiffTag > SPtr
Definition: fiff_tag.h:152
MNELIB::MNEForwardSolution::src
MNESourceSpace src
Definition: mne_forwardsolution.h:529
FIFFLIB::FiffStream::write_float
fiff_long_t write_float(fiff_int_t kind, const float *data, fiff_int_t nel=1)
Definition: fiff_stream.cpp:2628
FIFFLIB::FiffCoordTrans::from
fiff_int_t from
Definition: fiff_coord_trans.h:295
MNELIB::MNEForwardSolution::info
FIFFLIB::FiffInfoBase info
Definition: mne_forwardsolution.h:520
FIFFLIB::FiffCov
covariance data
Definition: fiff_cov.h:77
MNELIB::MNESourceSpace::readFromStream
static bool readFromStream(FIFFLIB::FiffStream::SPtr &p_pStream, bool add_geom, MNESourceSpace &p_SourceSpace)
Definition: mne_sourcespace.cpp:253
MNELIB::MNEInverseOperator::noisenorm
Eigen::SparseMatrix< double > noisenorm
Definition: mne_inverse_operator.h:379
MNELIB::MNEInverseOperator
Inverse operator.
Definition: mne_inverse_operator.h:141
MNELIB::RegionMT::iLabelIdxIn
qint32 iLabelIdxIn
Definition: mne_inverse_operator.h:110
FIFFLIB::FiffInfoBase::chs
QList< FiffChInfo > chs
Definition: fiff_info_base.h:223
FSLIB::Colortable
Vertices label based lookup table.
Definition: colortable.h:67
MNELIB::MNESourceSpace::get_vertno
QList< Eigen::VectorXi > get_vertno() const
Definition: mne_sourcespace.cpp:94
FIFFLIB::FiffStream::write_coord_trans
fiff_long_t write_coord_trans(const FiffCoordTrans &trans)
Definition: fiff_stream.cpp:2340
MNELIB::MNEInverseOperator::isFixedOrient
bool isFixedOrient() const
Definition: mne_inverse_operator.h:403
FIFFLIB::FiffStream::write_named_matrix
fiff_long_t write_named_matrix(fiff_int_t kind, const FiffNamedMatrix &mat)
Definition: fiff_stream.cpp:3039
FSLIB::Colortable::getLabelIds
Eigen::VectorXi getLabelIds() const
Definition: colortable.h:120
FIFFLIB::FiffInfoBase::channel_type
QString channel_type(qint32 idx) const
Definition: fiff_info_base.cpp:84
FIFFLIB::FiffCoordTrans::to
fiff_int_t to
Definition: fiff_coord_trans.h:296
MNELIB::MNEInverseOperator::methods
FIFFLIB::fiff_int_t methods
Definition: mne_inverse_operator.h:357
FIFFLIB::FiffInfoBase::ch_names
QStringList ch_names
Definition: fiff_info_base.h:224
MNELIB::MNEInverseOperator::source_ori
FIFFLIB::fiff_int_t source_ori
Definition: mne_inverse_operator.h:358
MNELIB::MNEForwardSolution::source_nn
Eigen::MatrixX3f source_nn
Definition: mne_forwardsolution.h:531
MNELIB::MNEInverseOperator::write
void write(QIODevice &p_IODevice)
Definition: mne_inverse_operator.cpp:1345
MNELIB::MNEInverseOperator::nchan
FIFFLIB::fiff_int_t nchan
Definition: mne_inverse_operator.h:360
FIFFV_MNE_ORIENT_PRIOR_COV
#define FIFFV_MNE_ORIENT_PRIOR_COV
Definition: fiff_constants.h:453
MNELIB::RegionMT::sDistMeasure
QString sDistMeasure
Definition: mne_inverse_operator.h:112
FIFFLIB::FiffStream
FIFF File I/O routines.
Definition: fiff_stream.h:104
FIFFLIB::FiffCoordTrans
Coordinate transformation description.
Definition: fiff_coord_trans.h:74
MNELIB::MNEInverseOperator::coord_frame
FIFFLIB::fiff_int_t coord_frame
Definition: mne_inverse_operator.h:361
MNELIB::RegionMT
Definition: mne_inverse_operator.h:103
MNELIB::RegionMT::idcs
Eigen::VectorXi idcs
Definition: mne_inverse_operator.h:109
FIFFLIB::FiffNamedMatrix
A named matrix.
Definition: fiff_named_matrix.h:76
MNELIB::RegionMT::nClusters
qint32 nClusters
Definition: mne_inverse_operator.h:108
FIFF_MNE_SOURCE_ORIENTATION
#define FIFF_MNE_SOURCE_ORIENTATION
Definition: fiff_constants.h:367
MNELIB::MNEInverseOperator::whitener
Eigen::MatrixXd whitener
Definition: mne_inverse_operator.h:377
FIFFLIB::FiffStream::write_int
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)
Definition: fiff_stream.cpp:2977
FIFFLIB::FiffStream::start_block
fiff_long_t start_block(fiff_int_t kind)
Definition: fiff_stream.cpp:1921
MNELIB::MNESourceSpace::size
qint32 size() const
Definition: mne_sourcespace.h:333
MNELIB::MNEInverseOperator::cluster_kernel
Eigen::MatrixXd cluster_kernel(const FSLIB::AnnotationSet &p_AnnotationSet, qint32 p_iClusterSize, Eigen::MatrixXd &p_D, QString p_sMethod="cityblock") const
Definition: mne_inverse_operator.cpp:352
FIFF_MNE_INVERSE_SOURCE_ORIENTATIONS
#define FIFF_MNE_INVERSE_SOURCE_ORIENTATIONS
Definition: fiff_constants.h:394
MNELIB::MNEInverseOperator::proj
Eigen::MatrixXd proj
Definition: mne_inverse_operator.h:376
FIFF_MNE_SOURCE_SPACE_NPOINTS
#define FIFF_MNE_SOURCE_SPACE_NPOINTS
Definition: fiff_constants.h:343
MNELIB::MNESourceSpace::isEmpty
bool isEmpty() const
Definition: mne_sourcespace.h:326
FSLIB::Label::isEmpty
bool isEmpty() const
Definition: label.h:184
MNELIB::MNEForwardSolution::mri_head_t
FIFFLIB::FiffCoordTrans mri_head_t
Definition: mne_forwardsolution.h:528
FIFF_MNE_INVERSE_LEADS_WEIGHTED
#define FIFF_MNE_INVERSE_LEADS_WEIGHTED
Definition: fiff_constants.h:387
FIFFLIB::FiffCoordTrans::invert_transform
bool invert_transform()
Definition: fiff_coord_trans.cpp:120
FIFF_MNE_INVERSE_FIELDS
#define FIFF_MNE_INVERSE_FIELDS
Definition: fiff_constants.h:388
FIFF_MNE_INVERSE_SING
#define FIFF_MNE_INVERSE_SING
Definition: fiff_constants.h:389
FIFFV_MNE_DEPTH_PRIOR_COV
#define FIFFV_MNE_DEPTH_PRIOR_COV
Definition: fiff_constants.h:452
MNELIB::MNEInverseOperator::source_cov
FIFFLIB::FiffCov::SDPtr source_cov
Definition: mne_inverse_operator.h:368
MNELIB::MNEInverseOperator::reginv
Eigen::VectorXd reginv
Definition: mne_inverse_operator.h:378
MNELIB::MNEInverseOperator::noise_cov
FIFFLIB::FiffCov::SDPtr noise_cov
Definition: mne_inverse_operator.h:367
FIFF_MNE_INVERSE_LEADS
#define FIFF_MNE_INVERSE_LEADS
Definition: fiff_constants.h:386