66#include <QCoreApplication>
79#ifndef FIFFV_COIL_CTF_GRAD
80#define FIFFV_COIL_CTF_GRAD 5001
83#ifndef FIFFV_COIL_CTF_REF_MAG
84#define FIFFV_COIL_CTF_REF_MAG 5002
87#ifndef FIFFV_COIL_CTF_REF_GRAD
88#define FIFFV_COIL_CTF_REF_GRAD 5003
91#ifndef FIFFV_COIL_CTF_OFFDIAG_REF_GRAD
92#define FIFFV_COIL_CTF_OFFDIAG_REF_GRAD 5004
112,
r0(Eigen::Vector3f::Zero())
132 int fit_sphere_to_bem =
true;
141 qInfo(
"\nSetting up the BEM model using %s...",d->
bemname.toUtf8().constData());
142 qInfo(
"\nLoading surfaces...");
145 qInfo(
"Three-layer model surfaces loaded.");
151 qInfo(
"Homogeneous model surface loaded.");
154 qCritical(
"Cannot use a homogeneous model in EEG calculations.");
157 qInfo(
"\nLoading the solution matrix...");
160 qInfo(
"Employing the head->MRI coordinate transform with the BEM model.");
164 qInfo(
"BEM model %s is now set up",d->
bem_model->sol_name.toUtf8().constData());
168 if (fit_sphere_to_bem) {
170 float simplex_size = 2e-2;
179 d->
r0 = r0_vec.head<3>();
182 qInfo(
"Fitted sphere model origin : %6.1f %6.1f %6.1f mm rad = %6.1f mm.",
183 1000*d->
r0[0],1000*d->
r0[1],1000*d->
r0[2],1000*R);
185 d->
bem_funcs = std::make_unique<dipoleFitFuncsRec>();
196 qInfo(
"Compensation setup done.");
198 qInfo(
"MEG solution matrix...");
211 qInfo(
"\tEEG solution matrix...");
221 qCritical(
"EEG sphere model not defined.");
224 d->
sphere_funcs = std::make_unique<dipoleFitFuncsRec>();
249 qInfo(
"Sphere model origin : %6.1f %6.1f %6.1f mm.",
250 1000*d->
r0[0],1000*d->
r0[1],1000*d->
r0[2]);
292 Eigen::VectorXd stds;
296 qInfo(
"Using standard noise values "
297 "(MEG grad : %6.1f fT/cm MEG mag : %6.1f fT EEG : %6.1f uV)\n",
298 1e13*grad_std,1e15*mag_std,1e6*eeg_std);
302 nchan = nchan + meg->
ncoil();
304 nchan = nchan + eeg->
ncoil();
310 for (k = 0; k < meg->
ncoil(); k++, n++) {
311 if (meg->
coils[k]->is_axial_coil()) {
312 stds[n] = mag_std*mag_std;
317 stds[n] = 1e6*stds[n];
321 stds[n] = grad_std*grad_std;
326 for (k = 0; k < eeg->
ncoil(); k++, n++) {
327 stds[n] = eeg_std*eeg_std;
339 float nave_ratio =
static_cast<float>(f->
nave) /
static_cast<float>(
nave);
345 if (f->
noise->cov.size() > 0) {
346 qInfo(
"Decomposing the sensor noise covariance matrix...");
350 for (k = 0; k < f->
noise->ncov*(f->
noise->ncov+1)/2; k++)
351 f->
noise->cov[k] = nave_ratio*f->
noise->cov[k];
352 for (k = 0; k < f->
noise->ncov; k++) {
353 f->
noise->lambda[k] = nave_ratio*f->
noise->lambda[k];
354 if (f->
noise->lambda[k] < 0.0)
355 f->
noise->lambda[k] = 0.0;
361 for (k = 0; k < f->
noise->ncov; k++)
362 f->
noise->cov_diag[k] = nave_ratio*f->
noise->cov_diag[k];
363 qInfo(
"Decomposition not needed for a diagonal noise covariance matrix.");
367 qInfo(
"Effective nave is now %d",
nave);
376 float nave_ratio =
static_cast<float>(f->
nave) /
static_cast<float>(
nave);
384 if (f->
noise->cov.size() > 0) {
388 qInfo(
"Decomposing the noise covariance...");
389 if (f->
noise->cov.size() > 0) {
392 for (k = 0; k < f->
noise->ncov; k++) {
393 if (f->
noise->lambda[k] < 0.0)
394 f->
noise->lambda[k] = 0.0;
397 for (k = 0; k < f->
noise->ncov*(f->
noise->ncov+1)/2; k++)
398 f->
noise->cov[k] = nave_ratio*f->
noise->cov[k];
399 for (k = 0; k < f->
noise->ncov; k++) {
400 f->
noise->lambda[k] = nave_ratio*f->
noise->lambda[k];
401 if (f->
noise->lambda[k] < 0.0)
402 f->
noise->lambda[k] = 0.0;
408 for (k = 0; k < f->
noise->ncov; k++)
409 f->
noise->cov_diag[k] = nave_ratio*f->
noise->cov_diag[k];
410 qInfo(
"Decomposition not needed for a diagonal noise covariance matrix.");
414 qInfo(
"Effective nave is now %d",
nave);
454 float *w = wVec.data();
455 int nomit_meg, nomit_eeg,
nmeg,
neeg;
458 nomit_meg = nomit_eeg = 0;
465 bool selected =
false;
466 for (
int c = 0; c < meas->
nchan; c++) {
468 meas->
chs[c].ch_name,
469 Qt::CaseInsensitive) == 0) {
470 selected = sels[c] != 0;
485 if (
nmeg > 0 &&
nmeg - nomit_meg > 0 &&
nmeg - nomit_meg < min_nchan) {
486 qCritical(
"Too few MEG channels remaining");
489 if (
neeg > 0 &&
neeg - nomit_eeg > 0 &&
neeg - nomit_eeg < min_nchan) {
490 qCritical(
"Too few EEG channels remaining");
494 if (nomit_meg + nomit_eeg > 0) {
495 if (f->
noise->cov.size() > 0) {
496 for (j = 0; j < f->
noise->ncov; j++)
497 for (k = 0; k <= j; k++) {
502 for (j = 0; j < f->
noise->ncov; j++) {
503 f->
noise->cov_diag[j] *= w[j] * w[j];
523 const QString &measname,
528 const QString &badname,
529 const QString &noisename,
537 const QList<QString> &projnames,
541 auto res = std::make_unique<InvDipoleFitData>();
545 QStringList file_bads;
548 std::unique_ptr<MNECovMatrix> cov;
549 std::unique_ptr<FwdCoilSet> templates;
550 std::unique_ptr<MNECTFCompDataSet> comp_data;
551 std::unique_ptr<FwdCoilSet> comp_coils;
556 if (!mriname.isEmpty()) {
558 if (res->mri_head_t->isEmpty())
562 qWarning(
"Source of MRI / head transform required for the BEM model is missing");
566 float move[] = { 0.0, 0.0, 0.0 };
567 float rot[3][3] = { { 1.0, 0.0, 0.0 },
570 Eigen::Matrix3f rotMat;
571 rotMat << rot[0][0], rot[0][1], rot[0][2],
572 rot[1][0], rot[1][1], rot[1][2],
573 rot[2][0], rot[2][1], rot[2][2];
574 Eigen::Vector3f moveVec = Eigen::Map<Eigen::Vector3f>(move);
578 res->mri_head_t->print();
580 if (res->meg_head_t->isEmpty())
582 res->meg_head_t->print();
586 if (!badname.isEmpty()) {
589 nbad = badlist.size();
590 qInfo(
"%d bad channels read from %s.", nbad, badname.toUtf8().data());
593 QFile measFile(measname);
595 if (measStream->open()) {
596 file_bads = measStream->read_bad_channels(measStream->dirtree());
597 file_nbad = file_bads.size();
602 if (badlist.isEmpty())
604 for (k = 0; k < file_nbad; k++) {
605 badlist.append(file_bads[k]);
609 qInfo(
"%d bad channels read from the data file.",file_nbad);
611 qInfo(
"%d bad channels total.",nbad);
625 qInfo(
"Will use %3d MEG channels from %s",res->nmeg,measname.toUtf8().data());
627 qInfo(
"Will use %3d EEG channels from %s",res->neeg,measname.toUtf8().data());
629 int nch_total = res->nmeg + res->neeg;
630 res->ch_names.clear();
631 for (
int i = 0; i < nch_total; i++)
632 res->ch_names.append(res->chs[i].ch_name);
648 QString qPath = QString(QCoreApplication::applicationDirPath() +
"/../resources/general/coilDefinitions/coil_def.dat");
650 if ( !QCoreApplication::startingUp() )
651 qPath = QCoreApplication::applicationDirPath() + QString(
"/../resources/general/coilDefinitions/coil_def.dat");
652 else if (!file.exists())
653 qPath =
"../resources/general/coilDefinitions/coil_def.dat";
655 QByteArray coilfileBytes = qPath.toUtf8();
656 const char *coilfile = coilfileBytes.constData();
666 Q_ASSERT(res->meg_head_t);
667 res->meg_coils = templates->create_meg_coils(res->chs,
677 qInfo(
"Head coordinate coil definitions created.");
697 if (comp_data->ncomp > 0) {
698 QList<FiffChInfo> comp_chs;
701 qInfo(
"%d compensation data sets in %s",comp_data->ncomp,measname.toUtf8().data());
703 QFile compFile(measname);
705 if (!compStream->open())
709 if (!compStream->read_meas_info(compStream->dirtree(), compInfo, compInfoNode)) {
714 for (
int k = 0; k < compInfo.
chs.size(); k++) {
716 comp_chs.append(compInfo.
chs[k]);
722 comp_coils = templates->create_meg_coils(comp_chs,
729 qInfo(
"%d compensation channels in %s",comp_coils->ncoil(),measname.toUtf8().data());
749 if (res->proj && res->proj->nitems > 0) {
750 qInfo(
"Final projection operator is:");
751 { QTextStream errStream(stderr); res->proj->report(errStream,
"\t"); }
753 if (res->proj->assign_channels(res->ch_names,res->nmeg+res->neeg) ==
FAIL)
755 if (res->proj->make_proj() ==
FAIL)
759 qInfo(
"No projection will be applied to the data.");
764 if (!noisename.isEmpty()) {
767 qInfo(
"Read a %s noise-covariance matrix from %s",
768 cov->cov_diag.size() > 0 ?
"diagonal" :
"full", noisename.toUtf8().data());
771 if ((cov =
ad_hoc_noise(res->meg_coils.get(),res->eeg_els.get(),grad_std,mag_std,eeg_std)) ==
nullptr)
774 res->noise = cov->pick_chs_omit(res->ch_names,
782 qInfo(
"Picked appropriate channels from the noise-covariance matrix.");
788 if (res->proj && res->proj->nitems > 0 && res->proj->nvec > 0) {
789 if (res->proj->apply_cov(res->noise.get()) ==
FAIL)
791 qInfo(
"Projection applied to the covariance matrix.");
798 res->noise->revert_to_diag();
799 qInfo(
"Using only the main diagonal of the noise-covariance matrix.");
805 if (res->noise->cov.size() > 0) {
806 Eigen::Vector3f regs;
815 if (res->noise->classify_channels(res->chs,
816 res->nmeg+res->neeg) ==
FAIL)
821 for (k = 0, do_it = 0; k < res->noise->ncov; k++) {
823 regs[res->noise->ch_class[k]] > 0.0)
830 res->noise->regularize(regs);
832 qInfo(
"No regularization applied to the noise-covariance matrix");
838 qInfo(
"Decomposing the noise covariance...");
839 if (res->noise->cov.size() > 0) {
840 if (res->noise->decompose_eigen() ==
FAIL)
842 qInfo(
"Eigenvalue decomposition done.");
843 for (k = 0; k < res->noise->ncov; k++) {
844 if (res->noise->lambda[k] < 0.0)
845 res->noise->lambda[k] = 0.0;
849 qInfo(
"Decomposition not needed for a diagonal covariance matrix.");
850 if (res->noise->add_inv() ==
FAIL)
855 return res.release();
863 const Eigen::Vector3f& Q,
870 Eigen::VectorXf oneVec(data->
nchan);
875 qWarning(
"Cannot pick time: %7.1f ms",1000*time);
878 for (k = 0; k < data->
nchan; k++)
881 qInfo(
"%g ",1e15*oneVec[k]);
885 Eigen::MatrixXf fwd = Eigen::MatrixXf::Zero(nch, 3);
889 for (k = 0; k < data->
nchan; k++)
892 qInfo(
"%g ",1e15*(Q[0]*fwd(k,0)+Q[1]*fwd(k,1)+Q[2]*fwd(k,2)));
919 delete old; old =
nullptr;
923 res->
fwd.resize(m, nch);
924 res->
uu.resize(m, nch);
925 res->
vv.resize(m, m);
928 res->
rd.resize(ndip, 3);
933 for (k = 0; k < ndip; k++) {
934 res->
rd.row(k) = Eigen::Map<const Eigen::Vector3f>(rd[k]);
938 Eigen::MatrixXf this_fwd(d->
nmeg + d->
neeg, 3);
939 Eigen::Map<const Eigen::Vector3f> rd_k(rd[k]);
945 for (
int p = 0; p < 3; p++)
946 res->
fwd.row(3*k+p) = this_fwd.col(p).transpose();
952 for (p = 0; p < 3; p++)
953 S[p] = res->
fwd.row(3*k+p).squaredNorm();
955 for (p = 0; p < 3; p++)
956 res->
scales[3*k+p] = sqrt(S[p]);
962 res->
scales[3*k+0] = res->
scales[3*k+1] = res->
scales[3*k+2] = sqrt(S[0]+S[1]+S[2])/3.0;
964 for (p = 0; p < 3; p++) {
965 if (res->
scales[3*k+p] > 0.0) {
967 res->
fwd.row(3*k+p) *= res->
scales[3*k+p];
988 int udim = std::min(m,n);
989 JacobiSVD<MatrixXf> svd(res->
fwd, ComputeFullU | ComputeFullV);
990 res->
sing = svd.singularValues();
991 res->
uu = svd.matrixV().transpose().topRows(udim);
992 res->
vv = svd.matrixU().transpose().topRows(udim);
1004 const Eigen::Vector3f& rd,
1008 rds[0] =
const_cast<float*
>(rd.data());
1017static float fit_eval(
const VectorXf& rd,
const void *user)
1028 qInfo(
"ncomp = %d",ncomp);
1030 Eigen::Map<const VectorXf> Bmap(fuser->
B, fwd->
nch);
1031 for (c = 0, Bm2 = 0.0; c < ncomp; c++) {
1032 one = fwd->
uu.row(c).dot(Bmap);
1033 Bm2 = Bm2 + one*one;
1035 return fuser->
B2-Bm2;
1041static int find_best_guess(
const Eigen::Ref<const Eigen::VectorXf>& B,
1049 double B2,Bm2,this_good,one;
1055 B2 = B.squaredNorm();
1056 for (k = 0; k < guess->
nguess; k++) {
1058 if (fwd->
nch == nch) {
1059 ncomp = fwd->
sing[2]/fwd->
sing[0] > limit ? 3 : 2;
1060 for (c = 0, Bm2 = 0.0; c < ncomp; c++) {
1061 one = fwd->
uu.row(c).dot(B);
1062 Bm2 = Bm2 + one*one;
1064 this_good = 1.0 - (B2 - Bm2)/B2;
1065 if (this_good > good) {
1072 qWarning(
"No reasonable initial guess found.");
1083static MatrixXf make_initial_dipole_simplex(
const Eigen::Vector3f& r0,
1092 float x = sqrt(3.0f)/3.0f;
1093 float r = sqrt(6.0f)/12.0f;
1096 float rr[][3] = { { x , 0.0f, -r },
1099 { 0.0f, 0.0f, R } };
1101 MatrixXf simplex = MatrixXf::Zero(4, 3);
1103 for (
int j = 0; j < 4; j++) {
1104 simplex.row(j) = Eigen::Map<const Vector3f>(rr[j]).transpose() * size + r0.transpose();
1109static bool dipole_report_func(
int loop,
1110 const VectorXf& fitpar,
1115 qInfo(
"loop %d rd %7.2f %7.2f %7.2f fval %g %g par diff %g",
1116 loop,1000*fitpar[0],1000*fitpar[1],1000*fitpar[2],fval_lo,fval_hi,1000*par_diff);
1125 const Eigen::Ref<const Eigen::VectorXf>& B,
1126 const Eigen::Vector3f& rd,
1139 ncomp = fwd->
sing[2]/fwd->
sing[0] > limit ? 3 : 2;
1142 for (c = 0, Bm2 = 0.0; c < ncomp; c++) {
1143 one = fwd->
uu.row(c).dot(B);
1144 Q += (one/fwd->
sing[c]) * fwd->
vv.row(c).head(3).transpose();
1145 Bm2 = Bm2 + one*one;
1150 for (c = 0; c < 3; c++)
1151 Q[c] = fwd->
scales[c]*Q[c];
1152 res = B.squaredNorm() - Bm2;
1175 Eigen::Ref<Eigen::VectorXf> B,
1183 float ftol[] = { 1e-2f, 1e-2f };
1184 float atol[] = { 0.2e-3f, 0.2e-3f };
1187 int max_eval = 1000;
1188 int report_interval = verbose ? 1 : -1;
1191 float good,final_val;
1192 Eigen::Vector3f rd_final, Q;
1194 int k,neval,neval_tot,nchan,ncomp;
1201 if (fit->
proj && fit->
proj->project_vector(B.data(),nchan,
true) ==
FAIL)
1204 if (fit->
noise->whiten_vector(B,B,nchan) ==
FAIL)
1209 if (find_best_guess(B,nchan,guess,limit,best,good) < 0)
1214 user.B2 = B.squaredNorm();
1216 user.report_dim =
false;
1219 rd_guess = guess->
rr.row(best).transpose();
1220 rd_final = rd_guess;
1224 for (k = 0; k < ntol; k++) {
1233 MatrixXf simplexMat = make_initial_dipole_simplex(rd_guess,size);
1234 for (
int p = 0; p < 4; p++)
1235 vals[p] = fit_eval(simplexMat.row(p),fit);
1246 dipole_report_func)) {
1252 float rv = 2.0f*(vals.maxCoeff()-vals.minCoeff())/(vals.maxCoeff()+vals.minCoeff());
1253 qWarning(
"Warning (t = %8.1f ms) : g = %6.1f %% final val = %7.3f rtol = %f",
1254 1000*time,100*(1 - vals[0]/
user.B2),vals[0],rv);
1258 rd_final = simplexMat.row(0).transpose();
1259 rd_guess = simplexMat.row(0).transpose();
1262 final_val = vals[0];
1270 if (fit_Q(fit,B,rd_final,
user.limit,Q,ncomp,final_val) ==
OK) {
1275 res.
good = 1.0 - final_val/
user.B2;
1278 res.
khi2 = final_val;
1280 res.
nfree = nchan-3-ncomp-fit->
proj->nvec;
1282 res.
nfree = nchan-3-ncomp;
1283 res.
neval = neval_tot;
1303 static const Eigen::Vector3f Qx(1.0f, 0.0f, 0.0f);
1304 static const Eigen::Vector3f Qy(0.0f, 1.0f, 0.0f);
1305 static const Eigen::Vector3f Qz(0.0f, 0.0f, 1.0f);
1318 Eigen::MatrixXf vec_meg(3,
nmeg);
1321 fwd.topRows(
nmeg) = vec_meg.transpose();
1323 auto fwd0 = fwd.col(0).head(
nmeg);
1324 auto fwd1 = fwd.col(1).head(
nmeg);
1325 auto fwd2 = fwd.col(2).head(
nmeg);
1342 Eigen::MatrixXf vec_eeg(3,
neeg);
1345 fwd.block(d.
nmeg, 0,
neeg, 3) = vec_eeg.transpose();
1347 auto fwd0 = fwd.col(0).segment(d.
nmeg,
neeg);
1348 auto fwd1 = fwd.col(1).segment(d.
nmeg,
neeg);
1349 auto fwd2 = fwd.col(2).segment(d.
nmeg,
neeg);
1362 for (k = 0; k < 3; k++)
1363 if (d.
proj && d.
proj->project_vector(fwd.col(k).data(),nch,
true) ==
FAIL)
1369 if (d.
noise && whiten) {
1370 for (k = 0; k < 3; k++) {
1371 auto col_k = fwd.col(k);
1372 if (d.
noise->whiten_vector(col_k,col_k,nch) ==
FAIL)
#define FIFFV_COIL_CTF_OFFDIAG_REF_GRAD
InvDipoleForward * dipole_forward(InvDipoleFitData *d, float **rd, int ndip, InvDipoleForward *old)
Compute the forward solution for one or more dipoles, applying projections and whitening.
void print_fields(const Eigen::Vector3f &rd, const Eigen::Vector3f &Q, float time, float integ, InvDipoleFitData *fit, MNEMeasData *data)
Dipole Fit Data class declaration.
constexpr int COLUMN_NORM_NONE
constexpr int COLUMN_NORM_COMP
constexpr int COLUMN_NORM_LOC
InvGuessData class declaration.
Electric Current Dipole (InvEcd) class declaration.
FiffInfo class declaration.
#define FIFFV_MNE_SENSOR_COV
#define FIFFV_COIL_CTF_REF_GRAD
#define FIFFV_MNE_NOISE_COV
#define FIFFV_COIL_CTF_REF_MAG
#define FIFFV_COORD_UNKNOWN
FiffStream class declaration.
#define FIFFV_BEM_SURF_ID_BRAIN
FiffCoordTrans class declaration.
MNECovMatrix class declaration.
#define MNE_COV_CH_MEG_MAG
#define MNE_COV_CH_MEG_GRAD
#define MNE_COV_CH_UNKNOWN
MNEProjItem class declaration.
MNESurface class declaration.
MNEMeasDataSet class declaration.
MNEMeasData class declaration.
SimplexAlgorithm Template Implementation.
Sphere class declaration.
Forward library type definitions.
FwdCompData class declaration.
FwdBemModel class declaration.
Core MNE data structures (source spaces, source estimates, hemispheres).
FIFF file I/O and data structures (raw, epochs, evoked, covariance, forward).
Inverse source estimation (MNE, dSPM, sLORETA, dipole fitting).
Forward modelling (BEM, MEG/EEG lead fields).
constexpr int FWD_COIL_ACCURACY_NORMAL
constexpr int FWD_COIL_ACCURACY_ACCURATE
constexpr int FWD_BEM_UNKNOWN
QSharedPointer< FiffDirNode > SPtr
FIFF measurement file information.
static bool readMegEegChannels(const QString &name, bool do_meg, bool do_eeg, const QStringList &bads, QList< FiffChInfo > &chsp, int &nmegp, int &neegp)
static bool readBadChannelsFromFile(const QString &name, QStringList &listOut)
QSharedPointer< FiffStream > SPtr
static FwdBemModel::UPtr fwd_bem_load_three_layer_surfaces(const QString &name)
Load a three-layer BEM model (scalp, outer skull, inner skull) from a FIFF file.
static int fwd_mag_dipole_field_vec(const Eigen::Vector3f &rm, FwdCoilSet &coils, Eigen::Ref< Eigen::MatrixXf > Bval, void *client)
Callback: compute the vector magnetic field of a magnetic dipole at coils.
static QString fwd_bem_make_bem_sol_name(const QString &name)
Build a standard BEM solution file name from a model name.
static int fwd_mag_dipole_field(const Eigen::Vector3f &rm, const Eigen::Vector3f &M, FwdCoilSet &coils, Eigen::Ref< Eigen::VectorXf > Bval, void *client)
Callback: compute the magnetic field of a magnetic dipole at coils.
static int fwd_sphere_field(const Eigen::Vector3f &rd, const Eigen::Vector3f &Q, FwdCoilSet &coils, Eigen::Ref< Eigen::VectorXf > Bval, void *client)
Callback: compute the spherical-model magnetic field at coils.
static int fwd_bem_field(const Eigen::Vector3f &rd, const Eigen::Vector3f &Q, FwdCoilSet &coils, Eigen::Ref< Eigen::VectorXf > B, void *client)
Callback: compute BEM magnetic fields at coils for a dipole.
static int fwd_bem_pot_els(const Eigen::Vector3f &rd, const Eigen::Vector3f &Q, FwdCoilSet &els, Eigen::Ref< Eigen::VectorXf > pot, void *client)
Callback: compute BEM potentials at electrodes for a dipole.
static FwdBemModel::UPtr fwd_bem_load_homog_surface(const QString &name)
Load a single-layer (homogeneous) BEM model from a FIFF file.
static int fwd_sphere_field_vec(const Eigen::Vector3f &rd, FwdCoilSet &coils, Eigen::Ref< Eigen::MatrixXf > Bval, void *client)
Callback: compute the spherical-model vector magnetic field at coils.
Collection of FwdCoil objects representing a full MEG or EEG sensor array.
static FwdCoilSet::UPtr read_coil_defs(const QString &name)
static FwdCoilSet::UPtr create_eeg_els(const QList< FIFFLIB::FiffChInfo > &chs, int nch, const FIFFLIB::FiffCoordTrans &t=FIFFLIB::FiffCoordTrans())
std::vector< FwdCoil::UPtr > coils
This structure is used in the compensated field calculations.
static int fwd_comp_field_vec(const Eigen::Vector3f &rd, FwdCoilSet &coils, Eigen::Ref< Eigen::MatrixXf > res, void *client)
static int fwd_comp_field(const Eigen::Vector3f &rd, const Eigen::Vector3f &Q, FwdCoilSet &coils, Eigen::Ref< Eigen::VectorXf > res, void *client)
static FwdCompData * fwd_make_comp_data(MNELIB::MNECTFCompDataSet *set, FwdCoilSet *coils, FwdCoilSet *comp_coils, fwdFieldFunc field, fwdVecFieldFunc vec_field, fwdFieldGradFunc field_grad, void *client)
Multi-layer spherical head model for EEG forward computation.
static int fwd_eeg_spherepot_coil_vec(const Eigen::Vector3f &rd, FwdCoilSet &els, Eigen::Ref< Eigen::MatrixXf > Vval_vec, void *client)
static int fwd_eeg_spherepot_coil(const Eigen::Vector3f &rd, const Eigen::Vector3f &Q, FwdCoilSet &els, Eigen::Ref< Eigen::VectorXf > Vval, void *client)
Forward field computation function pointers and client data for MEG and EEG dipole fitting.
fwdVecFieldFunc eeg_vec_pot
fwdVecFieldFunc meg_vec_field
MNELIB::mneUserFreeFunc meg_client_free
Workspace for the dipole fitting objective function, holding forward model, measured field,...
Dipole fit workspace holding sensor geometry, forward model, noise covariance, and projection data.
std::unique_ptr< FWDLIB::FwdEegSphereModel > eeg_model
virtual ~InvDipoleFitData()
std::unique_ptr< FWDLIB::FwdCoilSet > meg_coils
static InvDipoleFitData * setup_dipole_fit_data(const QString &mriname, const QString &measname, const QString &bemname, Eigen::Vector3f *r0, FWDLIB::FwdEegSphereModel *eeg_model, int accurate_coils, const QString &badname, const QString &noisename, float grad_std, float mag_std, float eeg_std, float mag_reg, float grad_reg, float eeg_reg, int diagnoise, const QList< QString > &projnames, int include_meg, int include_eeg)
Master setup: read all inputs and build a ready-to-use fit workspace.
std::unique_ptr< FIFFLIB::FiffCoordTrans > mri_head_t
static int scale_dipole_fit_noise_cov(InvDipoleFitData *f, int nave)
Scale dipole-fit noise covariance for a given number of averages.
std::unique_ptr< MNELIB::MNEProjOp > proj
static InvDipoleForward * dipole_forward_one(InvDipoleFitData *d, const Eigen::Vector3f &rd, InvDipoleForward *old)
Compute the forward solution for a single dipole position.
std::unique_ptr< MNELIB::MNECovMatrix > noise
std::unique_ptr< dipoleFitFuncsRec > bem_funcs
static int scale_noise_cov(InvDipoleFitData *f, int nave)
Scale the noise-covariance matrix for a given number of averages.
std::unique_ptr< dipoleFitFuncsRec > sphere_funcs
static bool fit_one(InvDipoleFitData *fit, InvGuessData *guess, float time, Eigen::Ref< Eigen::VectorXf > B, int verbose, InvEcd &res)
Fit a single dipole to the given data.
static int compute_dipole_field(InvDipoleFitData &d, const Eigen::Vector3f &rd, int whiten, Eigen::Ref< Eigen::MatrixXf > fwd)
Compute the forward field for a dipole at the given location.
static int setup_forward_model(InvDipoleFitData *d, MNELIB::MNECTFCompDataSet *comp_data, FWDLIB::FwdCoilSet *comp_coils)
Set up the sphere-model and (optionally) BEM forward functions.
std::unique_ptr< FWDLIB::FwdBemModel > bem_model
static int select_dipole_fit_noise_cov(InvDipoleFitData *f, MNELIB::MNEMeasData *meas, int nave, const int *sels)
Select and weight the noise-covariance for the active channel set.
std::unique_ptr< FWDLIB::FwdCoilSet > eeg_els
std::unique_ptr< dipoleFitFuncsRec > mag_dipole_funcs
static std::unique_ptr< MNELIB::MNECovMatrix > ad_hoc_noise(FWDLIB::FwdCoilSet *meg, FWDLIB::FwdCoilSet *eeg, float grad_std, float mag_std, float eeg_std)
Create an ad-hoc diagonal noise-covariance matrix.
std::unique_ptr< MNELIB::MNECovMatrix > noise_orig
dipoleFitFuncsRec * funcs
Stores forward field matrices and SVD decomposition for magnetic dipole fitting.
Eigen::Matrix< float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > uu
Eigen::Matrix< float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > vv
Eigen::Matrix< float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > fwd
Single equivalent current dipole with position, orientation, amplitude, and goodness-of-fit.
Precomputed guess point grid with forward fields for initial dipole position candidates.
std::vector< InvDipoleForward::UPtr > guess_fwd
Eigen::Matrix< float, Eigen::Dynamic, 3, Eigen::RowMajor > rr
static bool simplex_minimize(Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > &p, Eigen::Matrix< T, Eigen::Dynamic, 1 > &y, T ftol, T stol, T(*func)(const Eigen::Matrix< T, Eigen::Dynamic, 1 > &x, const void *user_data), const void *user_data, int max_eval, int &neval, int report, bool(*report_func)(int loop, const Eigen::Matrix< T, Eigen::Dynamic, 1 > &fitpar, double fval_lo, double fval_hi, double par_diff))
static bool fit_sphere_to_points(const Eigen::MatrixXf &rr, float simplex_size, Eigen::VectorXf &r0, float &R)
static std::unique_ptr< MNECovMatrix > read(const QString &name, int kind)
static std::unique_ptr< MNECovMatrix > create(int kind, int ncov, const QStringList &names, const Eigen::VectorXd &cov, const Eigen::VectorXd &cov_diag)
static int lt_packed_index(int j, int k)
Collection of CTF third-order gradient compensation operators.
static std::unique_ptr< MNECTFCompDataSet > read(const QString &name)
Measurement data container for MNE inverse and dipole-fit computations.
QList< FIFFLIB::FiffChInfo > chs
int getValuesAtTime(float time, float integ, int nch, bool use_abs, float *value) const
static bool makeProjection(const QList< QString > &projnames, const QList< FIFFLIB::FiffChInfo > &chs, int nch, std::unique_ptr< MNEProjOp > &result)
Load and combine SSP projection operators from files for the selected channels.
static FiffCoordTrans readMriTransform(const QString &name)
static FiffCoordTrans readMeasTransform(const QString &name)
Eigen::MatrixX3f apply_trans(const Eigen::MatrixX3f &rr, bool do_move=true) const
static QString frame_name(int frame)