159 const QString &method,
162 SparseMatrix<double> &noise_norm,
163 QList<VectorXi> &vertno)
167 if(method.compare(QLatin1String(
"MNE")) != 0)
170 vertno =
src.get_vertno();
172 typedef Eigen::Triplet<double> T;
173 std::vector<T> tripletList;
177 qWarning(
"Label selection needs further debugging.");
179 vertno =
src.label_src_vertno_sel(label, src_sel);
181 if(method.compare(QLatin1String(
"MNE")) != 0)
184 tripletList.reserve(noise_norm.nonZeros());
186 for (qint32 k = 0; k < noise_norm.outerSize(); ++k)
188 for (SparseMatrix<double>::InnerIterator it(noise_norm,k); it; ++it)
191 for(qint32 i = 0; i < src_sel.size(); ++i)
193 if(src_sel[i] == it.row())
200 tripletList.push_back(T(it.row(), it.col(), it.value()));
204 noise_norm = SparseMatrix<double>(src_sel.size(),noise_norm.cols());
205 noise_norm.setFromTriplets(tripletList.begin(), tripletList.end());
210 VectorXi src_sel_new(src_sel.size()*3);
212 for(qint32 i = 0; i < src_sel.size(); ++i)
214 src_sel_new[i*3] = src_sel[i]*3;
215 src_sel_new[i*3+1] = src_sel[i]*3+1;
216 src_sel_new[i*3+2] = src_sel[i]*3+2;
218 src_sel = src_sel_new;
221 for(qint32 i = 0; i < src_sel.size(); ++i)
223 t_eigen_leads.row(i) = t_eigen_leads.row(src_sel[i]);
224 t_source_cov = t_source_cov.row(src_sel[i]);
226 t_eigen_leads.conservativeResize(src_sel.size(), t_eigen_leads.cols());
227 t_source_cov.conservativeResize(src_sel.size(), t_source_cov.cols());
234 qWarning(
"Warning: Pick normal can only be used with a free orientation inverse operator.\n");
241 qWarning(
"The pick_normal parameter is only valid when working with loose orientations.\n");
247 for(qint32 i = 2; i < t_eigen_leads.rows(); i+=3)
249 t_eigen_leads.row(count) = t_eigen_leads.row(i);
252 t_eigen_leads.conservativeResize(count, t_eigen_leads.cols());
255 for(qint32 i = 2; i < t_source_cov.rows(); i+=3)
257 t_source_cov.row(count) = t_source_cov.row(i);
260 t_source_cov.conservativeResize(count, t_source_cov.cols());
264 tripletList.reserve(
reginv.rows());
265 for(qint32 i = 0; i <
reginv.rows(); ++i)
266 tripletList.push_back(T(i, i,
reginv(i,0)));
267 SparseMatrix<double> t_reginv(
reginv.rows(),
reginv.rows());
268 t_reginv.setFromTriplets(tripletList.begin(), tripletList.end());
280 printf(
"(eigenleads already weighted)...\n");
281 K = t_eigen_leads*trans;
288 printf(
"(eigenleads need to be weighted)...\n");
290 std::vector<T> tripletList2;
291 tripletList2.reserve(t_source_cov.rows());
292 for(qint32 i = 0; i < t_source_cov.rows(); ++i)
293 tripletList2.push_back(T(i, i, sqrt(t_source_cov(i,0))));
294 SparseMatrix<double> t_sourceCov(t_source_cov.rows(),t_source_cov.rows());
295 t_sourceCov.setFromTriplets(tripletList2.begin(), tripletList2.end());
297 K = t_sourceCov*t_eigen_leads*trans;
300 if(method.compare(QLatin1String(
"MNE")) == 0)
301 noise_norm = SparseMatrix<double>();
358 printf(
"Cluster kernel using %s.\n", p_sMethod.toUtf8().constData());
360 MatrixXd p_outMT = m_K.transpose();
362 QList<MNEClusterInfo> t_qListMNEClusterInfo;
364 t_qListMNEClusterInfo.append(t_MNEClusterInfo);
365 t_qListMNEClusterInfo.append(t_MNEClusterInfo);
372 printf(
"Error: Fixed orientation not implemented yet!\n");
384 for(qint32 h = 0; h < this->
src.size(); ++h )
391 for(qint32 j = 0; j < h; ++j)
392 offset += this->
src[j].nuse;
395 printf(
"Cluster Left Hemisphere\n");
397 printf(
"Cluster Right Hemisphere\n");
399 FsColortable t_CurrentColorTable = p_AnnotationSet[h].getColortable();
400 VectorXi label_ids = t_CurrentColorTable.
getLabelIds();
403 VectorXi vertno_labeled = VectorXi::Zero(this->
src[h].vertno.rows());
405 for(qint32 i = 0; i < vertno_labeled.rows(); ++i)
406 vertno_labeled[i] = p_AnnotationSet[h].getLabelIds()[this->
src[h].vertno[i]];
409 QList<RegionMT> m_qListRegionMTIn;
414 for (qint32 i = 0; i < label_ids.rows(); ++i)
416 if (label_ids[i] != 0)
418 QString curr_name = t_CurrentColorTable.
struct_names[i];
419 printf(
"\tCluster %d / %ld %s...", i+1, label_ids.rows(), curr_name.toUtf8().constData());
424 VectorXi idcs = VectorXi::Zero(vertno_labeled.rows());
428 for(qint32 j = 0; j < vertno_labeled.rows(); ++j)
430 if(vertno_labeled[j] == label_ids[i])
436 idcs.conservativeResize(c);
439 MatrixXd t_MT(p_outMT.rows(), idcs.rows()*3);
441 for(qint32 j = 0; j < idcs.rows(); ++j)
442 t_MT.block(0, j*3, t_MT.rows(), 3) = p_outMT.block(0, (idcs[j]+offset)*3, t_MT.rows(), 3);
444 qint32 nSens = t_MT.rows();
445 qint32 nSources = t_MT.cols()/3;
451 t_sensMT.
idcs = idcs;
453 t_sensMT.
nClusters = ceil(
static_cast<double>(nSources)/
static_cast<double>(p_iClusterSize));
457 printf(
"%d Cluster(s)... ", t_sensMT.
nClusters);
460 t_sensMT.
matRoiMT = MatrixXd(t_MT.cols()/3, 3*nSens);
462 for(qint32 j = 0; j < nSens; ++j)
463 for(qint32 k = 0; k < t_sensMT.
matRoiMT.rows(); ++k)
464 t_sensMT.
matRoiMT.block(k,j*3,1,3) = t_MT.block(j,k*3,1,3);
468 m_qListRegionMTIn.append(t_sensMT);
474 printf(
"failed! FsLabel contains no sources.\n");
482 printf(
"Clustering... ");
483 QFuture< RegionMTOut > res;
485 res.waitForFinished();
490 MatrixXd t_MT_partial;
494 QList<RegionMT>::const_iterator itIn;
495 itIn = m_qListRegionMTIn.begin();
496 QFuture<RegionMTOut>::const_iterator itOut;
497 for (itOut = res.constBegin(); itOut != res.constEnd(); ++itOut)
499 nClusters = itOut->ctrs.rows();
500 nSens = itOut->ctrs.cols()/3;
501 t_MT_partial = MatrixXd::Zero(nSens, nClusters*3);
506 for(qint32 j = 0; j < nSens; ++j)
507 for(qint32 k = 0; k < nClusters; ++k)
508 t_MT_partial.block(j, k*3, 1, 3) = itOut->ctrs.block(k,j*3,1,3);
513 for(qint32 j = 0; j < nClusters; ++j)
515 VectorXi clusterIdcs = VectorXi::Zero(itOut->roiIdx.rows());
516 VectorXd clusterDistance = VectorXd::Zero(itOut->roiIdx.rows());
517 qint32 nClusterIdcs = 0;
518 for(qint32 k = 0; k < itOut->roiIdx.rows(); ++k)
520 if(itOut->roiIdx[k] == j)
522 clusterIdcs[nClusterIdcs] = itIn->idcs[k];
523 clusterDistance[nClusterIdcs] = itOut->D(k,j);
527 clusterIdcs.conservativeResize(nClusterIdcs);
528 clusterDistance.conservativeResize(nClusterIdcs);
530 VectorXi clusterVertnos = VectorXi::Zero(clusterIdcs.size());
531 for(qint32 k = 0; k < clusterVertnos.size(); ++k)
532 clusterVertnos(k) = this->
src[h].vertno[clusterIdcs(k)];
534 t_qListMNEClusterInfo[h].clusterVertnos.append(clusterVertnos);
541 if(t_MT_partial.rows() > 0 && t_MT_partial.cols() > 0)
543 t_MT_new.conservativeResize(t_MT_partial.rows(), t_MT_new.cols() + t_MT_partial.cols());
544 t_MT_new.block(0, t_MT_new.cols() - t_MT_partial.cols(), t_MT_new.rows(), t_MT_partial.cols()) = t_MT_partial;
547 for(qint32 k = 0; k < nClusters; ++k)
551 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());
552 double sqec_min = sqec;
554 for(qint32 j = 1; j < itIn->idcs.rows(); ++j)
556 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());
579 qint32 totalNumOfClust = 0;
580 for (qint32 h = 0; h < 2; ++h)
581 totalNumOfClust += t_qListMNEClusterInfo[h].clusterVertnos.size();
584 p_D = MatrixXd::Zero(p_outMT.cols(), totalNumOfClust);
586 p_D = MatrixXd::Zero(p_outMT.cols(), totalNumOfClust*3);
588 QList<VectorXi> t_vertnos =
src.get_vertno();
590 qint32 currentCluster = 0;
591 for (qint32 h = 0; h < 2; ++h)
593 int hemiOffset = h == 0 ? 0 : t_vertnos[0].size();
594 for(qint32 i = 0; i < t_qListMNEClusterInfo[h].clusterVertnos.size(); ++i)
597 Linalg::intersect(t_vertnos[h], t_qListMNEClusterInfo[h].clusterVertnos[i], idx_sel);
599 idx_sel.array() += hemiOffset;
601 double selectWeight = 1.0/idx_sel.size();
604 for(qint32 j = 0; j < idx_sel.size(); ++j)
605 p_D.col(currentCluster)[idx_sel(j)] = selectWeight;
609 qint32 clustOffset = currentCluster*3;
610 for(qint32 j = 0; j < idx_sel.size(); ++j)
612 qint32 idx_sel_Offset = idx_sel(j)*3;
614 p_D(idx_sel_Offset,clustOffset) = selectWeight;
616 p_D(idx_sel_Offset+1, clustOffset+1) = selectWeight;
618 p_D(idx_sel_Offset+2, clustOffset+2) = selectWeight;
641 bool limit_depth_chs)
649 if(fixed && loose > 0)
651 qWarning(
"Warning: When invoking make_inverse_operator with fixed = true, the loose parameter is ignored.\n");
655 if(is_fixed_ori && !fixed)
657 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");
663 qCritical(
"Forward solution is not oriented in surface coordinates. loose parameter should be 0 not %f.", loose);
667 if(loose < 0 || loose > 1)
669 qWarning(
"Warning: Loose value should be in interval [0,1] not %f.\n", loose);
670 loose = loose > 1 ? 1 : 0;
671 printf(
"Setting loose to %f.\n", loose);
674 if(depth < 0 || depth > 1)
676 qWarning(
"Warning: Depth value should be in interval [0,1] not %f.\n", depth);
677 depth = depth > 1 ? 1 : 0;
678 printf(
"Setting depth to %f.\n", depth);
698 MatrixXd patch_areas;
706 p_depth_prior->data = MatrixXd::Ones(gain.cols(), gain.cols());
708 p_depth_prior->diag =
true;
709 p_depth_prior->dim = gain.cols();
710 p_depth_prior->nfree = 1;
716 if(depth < 0 || depth > 1)
719 printf(
"\tPicking elements from free-orientation depth prior into fixed-orientation one.\n");
725 qWarning(
"Warning: For a fixed-orientation inverse, the forward solution must be surface-oriented. Skipping fixed conversion.\n");
731 for(qint32 i = 2; i < p_depth_prior->data.rows(); i+=3)
733 p_depth_prior->data.row(count) = p_depth_prior->data.row(i);
736 p_depth_prior->data.conservativeResize(count, 1);
744 printf(
"\tComputing inverse operator with %lld channels.\n", gain_info.
ch_names.size());
749 printf(
"\tCreating the source covariance matrix\n");
757 p_source_cov->data.array() *= p_orient_prior->data.array();
766 printf(
"\tWhitening the forward solution.\n");
777 printf(
"\tAdjusting source covariance matrix.\n");
778 RowVectorXd source_std = p_source_cov->data.array().sqrt().transpose();
780 for(qint32 i = 0; i < gain.rows(); ++i)
781 gain.row(i) = gain.row(i).array() * source_std.array();
783 double trace_GRGT = (gain * gain.transpose()).trace();
784 double scaling_source_cov =
static_cast<double>(n_nzero) / trace_GRGT;
786 p_source_cov->data.array() *= scaling_source_cov;
788 gain.array() *= sqrt(scaling_source_cov);
793 printf(
"Computing SVD of whitened and weighted lead field matrix.\n");
794 JacobiSVD<MatrixXd> svd(gain, ComputeThinU | ComputeThinV);
796 VectorXd p_sing = svd.singularValues();
797 MatrixXd t_U = svd.matrixU();
800 svd.matrixU().rows(),
805 p_sing = svd.singularValues();
806 MatrixXd t_V = svd.matrixV();
809 svd.matrixV().cols(),
813 printf(
"\tlargest singular value = %f\n", p_sing.maxCoeff());
814 printf(
"\tscaling factor to adjust the trace = %f\n", trace_GRGT);
819 bool has_meg =
false;
820 bool has_eeg =
false;
822 RowVectorXd ch_idx(
info.chs.size());
824 for(qint32 i = 0; i <
info.chs.size(); ++i)
832 ch_idx.conservativeResize(count);
834 for(qint32 i = 0; i < ch_idx.size(); ++i)
836 QString ch_type =
info.channel_type(ch_idx[i]);
837 if (ch_type ==
"eeg")
839 if ((ch_type ==
"mag") || (ch_type ==
"grad"))
845 if(has_eeg && has_meg)
859 inv.
nchan = p_sing.rows();
888 printf(
"The number of averages should be positive\n");
891 printf(
"Preparing the inverse operator for use...\n");
896 float scale =
static_cast<float>(inv.
nave)/
static_cast<float>(
nave);
904 printf(
"\tScaled noise and source covariance from nave = %d to nave = %d\n",inv.
nave,
nave);
909 VectorXd tmp = inv.
sing.cwiseProduct(inv.
sing) + VectorXd::Constant(inv.
sing.size(), lambda2);
910 inv.
reginv = VectorXd(inv.
sing.cwiseQuotient(tmp));
911 printf(
"\tCreated the regularized inverter\n");
918 printf(
"\tCreated an SSP operator (subspace dimension = %d)\n",ncomp);
933 for (k = ncomp; k < inv.
noise_cov->dim; ++k)
945 printf(
"\tCreated the whitener using a full noise covariance matrix (%d small eigenvalues omitted)\n", inv.
noise_cov->dim - nnzero);
955 printf(
"\tCreated the whitener using a diagonal noise covariance matrix (%d small eigenvalues discarded)\n",ncomp);
962 VectorXd noise_norm = VectorXd::Zero(inv.
eigen_leads->nrow);
963 VectorXd noise_weight;
966 printf(
"\tComputing noise-normalization factors (dSPM)...");
967 noise_weight = VectorXd(inv.
reginv);
971 printf(
"\tComputing noise-normalization factors (sLORETA)...");
972 VectorXd tmp = (VectorXd::Constant(inv.
sing.size(), 1) + inv.
sing.cwiseProduct(inv.
sing)/lambda2);
973 noise_weight = inv.
reginv.cwiseProduct(tmp.cwiseSqrt());
981 noise_norm[k] = sqrt(one.dot(one));
990 one = c*(inv.
eigen_leads->data.row(k).transpose()).cwiseProduct(noise_weight);
991 noise_norm[k] = sqrt(one.dot(one));
998 VectorXd noise_norm_new;
1004 noise_norm_new = t.cwiseSqrt();
1006 VectorXd vOnes = VectorXd::Ones(noise_norm_new.size());
1007 VectorXd tmp = vOnes.cwiseQuotient(noise_norm_new.cwiseAbs());
1009 typedef Eigen::Triplet<double> T;
1010 std::vector<T> tripletList;
1011 tripletList.reserve(noise_norm_new.size());
1012 for(qint32 i = 0; i < noise_norm_new.size(); ++i)
1013 tripletList.push_back(T(i, i, tmp[i]));
1015 inv.
noisenorm = SparseMatrix<double>(noise_norm_new.size(),noise_norm_new.size());
1016 inv.
noisenorm.setFromTriplets(tripletList.begin(), tripletList.end());
1036 printf(
"Reading inverse operator decomposition from %s...\n",t_pStream->streamName().toUtf8().constData());
1038 if(!t_pStream->open())
1044 if ( invs_list.size()== 0)
1046 printf(
"No inverse solutions in %s\n", t_pStream->streamName().toUtf8().constData());
1054 if (parent_mri.size() == 0)
1056 printf(
"No parent MRI information in %s", t_pStream->streamName().toUtf8().constData());
1059 printf(
"\tReading inverse operator info...");
1066 printf(
"Modalities not found\n");
1071 inv.
methods = *t_pTag->toInt();
1075 printf(
"Source orientation constraints not found\n");
1082 printf(
"Number of sources not found\n");
1085 inv.
nsource = *t_pTag->toInt();
1092 printf(
"Coordinate frame tag not found\n");
1101 printf(
"Source orientation information not found\n");
1105 inv.
source_nn = t_pTag->toFloatMatrix();
1112 printf(
"\tReading inverse operator decomposition...");
1115 printf(
"Singular values not found\n");
1119 inv.
sing = Map<VectorXf>(t_pTag->toFloat(), t_pTag->size()/4).cast<
double>();
1130 printf(
"Error reading eigenleads named matrix.\n");
1141 printf(
"Error reading eigenfields named matrix.\n");
1150 printf(
"\tNoise covariance matrix read.\n");
1154 printf(
"\tError: Not able to read noise covariance matrix.\n");
1160 printf(
"\tSource covariance matrix read.\n");
1164 printf(
"\tError: Not able to read source covariance matrix.\n");
1172 printf(
"\tOrientation priors read.\n");
1179 printf(
"\tDepth priors read.\n");
1187 printf(
"\tfMRI priors read.\n");
1198 printf(
"\tError: Could not read the source spaces.\n");
1201 for (qint32 k = 0; k < inv.
src.
size(); ++k)
1209 printf(
"MRI/head coordinate transformation not found\n");
1220 printf(
"MRI/head coordinate transformation not found");
1230 t_pStream->read_meas_info_base(t_pStream->dirtree(), inv.
info);
1237 printf(
"Only inverse solutions computed in MRI or head coordinates are acceptable");
1245 inv.
projs = t_pStream->read_proj(t_pStream->dirtree());
1251 printf(
"Could not transform source space.\n");
1253 printf(
"\tSource spaces transformed to the inverse solution coordinate frame\n");