59#include <QtConcurrent>
61#define _USE_MATH_DEFINES
66static float Qx[] = {1.0,0.0,0.0};
67static float Qy[] = {0.0,1.0,0.0};
68static float Qz[] = {0.0,0.0,1.0};
90#define VEC_DIFF_40(from,to,diff) {\
91 (diff)[X_40] = (to)[X_40] - (from)[X_40];\
92 (diff)[Y_40] = (to)[Y_40] - (from)[Y_40];\
93 (diff)[Z_40] = (to)[Z_40] - (from)[Z_40];\
96#define VEC_COPY_40(to,from) {\
97 (to)[X_40] = (from)[X_40];\
98 (to)[Y_40] = (from)[Y_40];\
99 (to)[Z_40] = (from)[Z_40];\
102#define VEC_DOT_40(x,y) ((x)[X_40]*(y)[X_40] + (x)[Y_40]*(y)[Y_40] + (x)[Z_40]*(y)[Z_40])
104#define VEC_LEN_40(x) sqrt(VEC_DOT_40(x,x))
106#define CROSS_PRODUCT_40(x,y,xy) {\
107 (xy)[X_40] = (x)[Y_40]*(y)[Z_40]-(y)[Y_40]*(x)[Z_40];\
108 (xy)[Y_40] = -((x)[X_40]*(y)[Z_40]-(y)[X_40]*(x)[Z_40]);\
109 (xy)[Z_40] = (x)[X_40]*(y)[Y_40]-(y)[X_40]*(x)[Y_40];\
112#define MALLOC_40(x,t) (t *)malloc((x)*sizeof(t))
114#define ALLOC_CMATRIX_40(x,y) mne_cmatrix_40((x),(y))
116#define FREE_40(x) if ((char *)(x) != NULL) free((char *)(x))
118#define FREE_CMATRIX_40(m) mne_free_cmatrix_40((m))
120void mne_free_cmatrix_40 (
float **m)
128static void matrix_error_40(
int kind,
int nr,
int nc)
132 printf(
"Failed to allocate memory pointers for a %d x %d matrix\n",nr,nc);
134 printf(
"Failed to allocate memory for a %d x %d matrix\n",nr,nc);
136 printf(
"Allocation error for a %d x %d matrix\n",nr,nc);
137 if (
sizeof(
void *) == 4) {
138 printf(
"This is probably because you seem to be using a computer with 32-bit architecture.\n");
139 printf(
"Please consider moving to a 64-bit platform.");
141 printf(
"Cannot continue. Sorry.\n");
145float **mne_cmatrix_40 (
int nr,
int nc)
152 m = MALLOC_40(nr,
float *);
153 if (!m) matrix_error_40(1,nr,nc);
154 whole = MALLOC_40(nr*nc,
float);
155 if (!whole) matrix_error_40(2,nr,nc);
163Eigen::MatrixXf toFloatEigenMatrix_40(
float **mat,
const int m,
const int n)
165 Eigen::MatrixXf eigen_mat(m,n);
167 for (
int i = 0; i < m; ++i)
168 for (
int j = 0; j < n; ++j)
169 eigen_mat(i,j) = mat[i][j];
174void fromFloatEigenMatrix_40(
const Eigen::MatrixXf& from_mat,
float **& to_mat,
const int m,
const int n)
176 for (
int i = 0; i < m; ++i)
177 for (
int j = 0; j < n; ++j)
178 to_mat[i][j] = from_mat(i,j);
181void fromFloatEigenMatrix_40(
const Eigen::MatrixXf& from_mat,
float **& to_mat)
183 fromFloatEigenMatrix_40(from_mat, to_mat, from_mat.rows(), from_mat.cols());
186float **mne_lu_invert_40(
float **mat,
int dim)
192 Eigen::MatrixXf eigen_mat = toFloatEigenMatrix_40(mat, dim, dim);
193 Eigen::MatrixXf eigen_mat_inv = eigen_mat.inverse();
194 fromFloatEigenMatrix_40(eigen_mat_inv, mat);
198void mne_transpose_square_40(
float **mat,
int n)
206 for (j = 1; j < n; j++)
207 for (
k = 0;
k < j;
k++) {
209 mat[j][
k] = mat[
k][j];
215float mne_dot_vectors_40(
float *v1,
222 float res = sdot(&nn,v1,&one,v2,&one);
228 for (
k = 0;
k < nn;
k++)
229 res = res + v1[
k]*v2[
k];
234void mne_add_scaled_vector_to_40(
float *v1,
float scale,
float *v2,
int nn)
238 float fscale = scale;
240 saxpy(&nn,&fscale,v1,&one,v2,&one);
243 for (
k = 0;
k < nn;
k++)
244 v2[
k] = v2[
k] + scale*v1[
k];
249void mne_scale_vector_40(
double scale,
float *v,
int nn)
253 float fscale = scale;
255 sscal(&nn,&fscale,v,&one);
258 for (
k = 0;
k < nn;
k++)
264using namespace Eigen;
266float **mne_mat_mat_mult_40 (
float **m1,
276 float **result = ALLOC_CMATRIX_40(d1,d3);
281 sgemm (transa,transb,&d3,&d1,&d2,
282 &one,m2[0],&d3,m1[0],&d2,&zero,result[0],&d3);
285 float **result = ALLOC_CMATRIX_40(d1,d3);
294 for (j = 0; j < d1; j++) {
295 for (
k = 0;
k < d2;
k++) {
300 for (j = 0; j < d2; j++) {
301 for (
k = 0;
k < d3;
k++) {
306 MatrixXf resultMat = a * b;
308 for (j = 0; j < d1; j++) {
309 for (
k = 0;
k < d3;
k++) {
310 result[j][
k] = resultMat(j,
k);
331} surf_expl[] = { { FIFFV_BEM_SURF_ID_BRAIN ,
"inner skull" },
332{ FIFFV_BEM_SURF_ID_SKULL ,
"outer skull" },
333{ FIFFV_BEM_SURF_ID_HEAD ,
"scalp" },
339} method_expl[] = { { FWD_BEM_CONSTANT_COLL ,
"constant collocation" },
340{ FWD_BEM_LINEAR_COLL ,
"linear collocation" },
345#define BEM_SUFFIX "-bem.fif"
346#define BEM_SOL_SUFFIX "-bem-sol.fif"
350static QString strip_from(
const QString& s,
const QString& suffix)
354 if (s.endsWith(suffix)) {
356 res.chop(suffix.size());
376const QString mne_coord_frame_name_40(
int frame)
380 {FIFFV_COORD_UNKNOWN,
"unknown"},
381 {FIFFV_COORD_DEVICE,
"MEG device"},
382 {FIFFV_COORD_ISOTRAK,
"isotrak"},
383 {FIFFV_COORD_HPI,
"hpi"},
384 {FIFFV_COORD_HEAD,
"head"},
385 {FIFFV_COORD_MRI,
"MRI (surface RAS)"},
387 {FIFFV_COORD_MRI_SLICE,
"MRI slice"},
388 {FIFFV_COORD_MRI_DISPLAY,
"MRI display"},
398 for (
k = 0; frames[
k].frame != -1;
k++) {
399 if (frame == frames[
k].frame)
400 return frames[
k].name;
402 return frames[
k].name;
409using namespace Eigen;
410using namespace FIFFLIB;
411using namespace MNELIB;
412using namespace FWDLIB;
426,bem_method (FWD_BEM_UNKNOWN)
431,use_ip_approach(false)
432,ip_approach_limit(FWD_BEM_IP_APPROACH_LIMIT)
440 for (
int k = 0;
k < this->nsurf;
k++)
441 delete this->surfs[
k];
444 FREE_40(this->sigma);
445 FREE_40(this->source_mult);
446 FREE_40(this->field_mult);
447 FREE_CMATRIX_40(this->gamma);
449 delete this->head_mri_t;
457 FREE_CMATRIX_40(this->solution); this->solution = NULL;
458 this->sol_name.clear();
459 FREE_40(this->v0); this->v0 = NULL;
460 this->bem_method = FWD_BEM_UNKNOWN;
475 s1 = strip_from(name,
".fif");
476 s2 = strip_from(s1,
"-sol");
477 s1 = strip_from(s2,
"-bem");
478 s2 = QString(
"%1%2").arg(s1).arg(BEM_SOL_SUFFIX);
484const QString& FwdBemModel::fwd_bem_explain_surface(
int kind)
488 for (
k = 0; surf_expl[
k].kind >= 0;
k++)
489 if (surf_expl[
k].kind == kind)
490 return surf_expl[
k].name;
492 return surf_expl[
k].name;
497const QString& FwdBemModel::fwd_bem_explain_method(
int method)
502 for (
k = 0; method_expl[
k].method >= 0;
k++)
503 if (method_expl[
k].method == method)
504 return method_expl[
k].name;
506 return method_expl[
k].name;
517 if(node->find_tag(stream, what, t_pTag)) {
518 if (t_pTag->getType() != FIFFT_INT) {
519 printf(
"Expected an integer tag : %d (found data type %d instead)\n",what,t_pTag->getType() );
522 *res = *t_pTag->toInt();
536 for (
int k = 0;
k < this->nsurf;
k++)
537 if (this->surfs[
k]->
id == kind)
538 return this->surfs[
k];
539 printf(
"Desired surface (%d = %s) not found.", kind,fwd_bem_explain_surface(kind).toUtf8().constData());
545FwdBemModel *FwdBemModel::fwd_bem_load_surfaces(
const QString &name,
int *kinds,
int nkind)
550 QList<MneSurfaceOld*> surfs;
557 qCritical(
"No surfaces specified to fwd_bem_load_surfaces");
562 sigma = MALLOC_40(nkind,
float);
566 for (
k = 0;
k < nkind;
k++) {
567 surfs.append(MneSurfaceOld::read_bem_surface(name,kinds[
k],TRUE,sigma+
k));
568 if (surfs[
k] == NULL)
570 if ((surfs[
k] = MneSurfaceOld::read_bem_surface(name,kinds[
k],TRUE,sigma+
k)) == NULL)
572 if (sigma[
k] < 0.0) {
573 qCritical(
"No conductivity available for surface %s",fwd_bem_explain_surface(kinds[
k]).toUtf8().constData());
576 if (surfs[
k]->coord_frame != FIFFV_COORD_MRI) {
577 qCritical(
"Surface %s not specified in MRI coordinates.",fwd_bem_explain_surface(kinds[
k]).toUtf8().constData());
587 m->ntri = MALLOC_40(nkind,
int);
588 m->np = MALLOC_40(nkind,
int);
589 m->gamma = ALLOC_CMATRIX_40(nkind,nkind);
590 m->source_mult = MALLOC_40(nkind,
float);
591 m->field_mult = MALLOC_40(nkind,
float);
595 sigma1 = MALLOC_40(nkind+1,
float);
598 for (
k = 0;
k < m->nsurf;
k++)
599 sigma[
k] = m->sigma[
k];
603 for (j = 0; j < m->nsurf; j++) {
604 m->ntri[j] = m->surfs[j]->ntri;
605 m->np[j] = m->surfs[j]->np;
606 m->source_mult[j] = 2.0/(sigma[j]+sigma[j-1]);
607 m->field_mult[j] = sigma[j]-sigma[j-1];
608 for (
k = 0;
k < m->nsurf;
k++)
609 m->gamma[j][
k] = (sigma[
k]-sigma[
k-1])/(sigma[j]+sigma[j-1]);
617 for (
k = 0;
k < surfs.size();
k++)
627FwdBemModel *FwdBemModel::fwd_bem_load_homog_surface(
const QString &name)
632 int kinds[] = { FIFFV_BEM_SURF_ID_BRAIN };
635 return fwd_bem_load_surfaces(name,kinds,nkind);
640FwdBemModel *FwdBemModel::fwd_bem_load_three_layer_surfaces(
const QString &name)
645 int kinds[] = { FIFFV_BEM_SURF_ID_HEAD, FIFFV_BEM_SURF_ID_SKULL, FIFFV_BEM_SURF_ID_BRAIN };
648 return fwd_bem_load_surfaces(name,kinds,nkind);
653int FwdBemModel::fwd_bem_load_solution(
const QString &name,
int bem_method,
FwdBemModel *m)
681 QList<FiffDirNode::SPtr> nodes = stream->dirtree()->dir_tree_find(
FIFFB_BEM);
683 if (nodes.size() == 0) {
684 printf (
"No BEM data in %s",name.toUtf8().constData());
695 method = FWD_BEM_CONSTANT_COLL;
697 method = FWD_BEM_LINEAR_COLL;
699 printf (
"Cannot handle BEM approximation method : %d",method);
702 if (bem_method != FWD_BEM_UNKNOWN && method != bem_method) {
703 printf(
"Approximation method in file : %d desired : %d",method,bem_method);
712 QVector<qint32> dims;
713 t_pTag->getMatrixDimensions(ndim, dims);
716 printf(
"Expected a two-dimensional solution matrix instead of a %d dimensional one",ndim);
719 for (
k = 0, dim = 0;
k < m->nsurf;
k++)
720 dim = dim + ((method == FWD_BEM_LINEAR_COLL) ? m->surfs[
k]->np : m->surfs[
k]->ntri);
721 if (dims[0] != dim || dims[1] != dim) {
722 printf(
"Expected a %d x %d solution matrix instead of a %d x %d one",dim,dim,dims[0],dims[1]);
726 MatrixXf tmp_sol = t_pTag->toFloatMatrix().transpose();
727 sol = ALLOC_CMATRIX_40(tmp_sol.rows(),tmp_sol.cols());
728 fromFloatEigenMatrix_40(tmp_sol, sol);
736 m->bem_method = method;
743 FREE_CMATRIX_40(sol);
749 FREE_CMATRIX_40(sol);
761 if (t->
from == FIFFV_COORD_HEAD && t->
to == FIFFV_COORD_MRI) {
763 delete m->head_mri_t;
767 else if (t->
from == FIFFV_COORD_MRI && t->
to == FIFFV_COORD_HEAD) {
769 delete m->head_mri_t;
770 m->head_mri_t = t->fiff_invert_transform();
774 printf (
"Improper coordinate transform delivered to fwd_bem_set_head_mri_t");
781MneSurfaceOld* FwdBemModel::make_guesses(
MneSurfaceOld* guess_surf,
float guessrad,
float *guess_r0,
float grid,
float exclude,
float mindist)
787 char *bemname = NULL;
792 float r0[] = { 0.0, 0.0, 0.0 };
798 printf(
"Making a spherical guess space with radius %7.1f mm...\n",1000*guessrad);
808 QFile bemFile(QString(QCoreApplication::applicationDirPath() +
"/../resources/general/surf2bem/icos.fif"));
809 if ( !QCoreApplication::startingUp() )
810 bemFile.setFileName(QCoreApplication::applicationDirPath() + QString(
"/../resources/general/surf2bem/icos.fif"));
811 else if (!bemFile.exists())
812 bemFile.setFileName(
"../resources/general/surf2bem/icos.fif");
814 if( !bemFile.exists () ){
815 qDebug() << bemFile.fileName() <<
"does not exists.";
819 bemname = MALLOC_40(strlen(bemFile.fileName().toUtf8().data())+1,
char);
820 strcpy(bemname,bemFile.fileName().toUtf8().data());
822 if ((sphere = MneSourceSpaceOld::read_bem_surface(bemname,9003,FALSE,NULL)) == NULL)
825 for (
k = 0;
k < sphere->np;
k++) {
826 dist = VEC_LEN_40(sphere->rr[
k]);
827 sphere->rr[
k][X_40] = guessrad*sphere->rr[
k][X_40]/dist + guess_r0[X_40];
828 sphere->rr[
k][Y_40] = guessrad*sphere->rr[
k][Y_40]/dist + guess_r0[Y_40];
829 sphere->rr[
k][Z_40] = guessrad*sphere->rr[
k][Z_40]/dist + guess_r0[Z_40];
831 if (MneSurfaceOrVolume::mne_source_space_add_geometry_info((
MneSourceSpaceOld*)sphere,TRUE) == FAIL)
836 printf(
"Guess surface (%d = %s) is in %s coordinates\n",
837 guess_surf->id,FwdBemModel::fwd_bem_explain_surface(guess_surf->id).toUtf8().constData(),
838 mne_coord_frame_name_40(guess_surf->coord_frame).toUtf8().constData());
840 printf(
"Filtering (grid = %6.f mm)...\n",1000*grid);
841 res = (
MneSurfaceOld*)MneSurfaceOrVolume::make_volume_source_space(guess_surf,grid,exclude,mindist);
853double FwdBemModel::calc_beta(
double *rk,
double *rk1)
860 VEC_DIFF_40(rk,rk1,rkk1);
861 size = VEC_LEN_40(rkk1);
863 res = log((VEC_LEN_40(rk)*size + VEC_DOT_40(rk,rkk1))/
864 (VEC_LEN_40(rk1)*size + VEC_DOT_40(rk1,rkk1)))/size;
870void FwdBemModel::lin_pot_coeff(
float *from,
MneTriangle* to,
double omega[])
875 double y1[3],y2[3],y3[3];
884 double beta[3],bbeta[3];
889 static const double solid_eps = 4.0*M_PI/1.0E6;
902 VEC_DIFF_40(from,to->r1,y1);
903 VEC_DIFF_40(from,to->r2,y2);
904 VEC_DIFF_40(from,to->r3,y3);
906 CROSS_PRODUCT_40(y1,y2,cross);
907 triple = VEC_DOT_40(cross,y3);
912 ss = (l1*l2*l3+VEC_DOT_40(y1,y2)*l3+VEC_DOT_40(y1,y3)*l2+VEC_DOT_40(y2,y3)*l1);
913 solid = 2.0*atan2(triple,ss);
914 if (std::fabs(solid) < solid_eps) {
915 for (
k = 0;
k < 3;
k++)
922 for (j = 0; j < 3; j++)
923 beta[j] = calc_beta(yy[j],yy[j+1]);
924 bbeta[0] = beta[2] - beta[0];
925 bbeta[1] = beta[0] - beta[1];
926 bbeta[2] = beta[1] - beta[2];
928 for (j = 0; j < 3; j++)
930 for (j = 0; j < 3; j++)
931 for (
k = 0;
k < 3;
k++)
932 vec_omega[
k] = vec_omega[
k] + bbeta[j]*yy[j][
k];
936 area2 = 2.0*to->area;
937 n2 = 1.0/(area2*area2);
938 for (
k = 0;
k < 3;
k++) {
939 CROSS_PRODUCT_40(yy[
k+1],yy[
k-1],z);
940 VEC_DIFF_40(yy[
k+1],yy[
k-1],diff);
941 omega[
k] = n2*(-area2*VEC_DOT_40(z,to->nn)*solid +
942 triple*VEC_DOT_40(diff,vec_omega));
951 rel1 = (solid + omega[X_40]+omega[Y_40]+omega[Z_40])/solid;
955 for (j = 0; j < 3; j++)
957 for (
k = 0;
k < 3;
k++) {
958 CROSS_PRODUCT_40(to->nn[to],yy[
k],z);
959 for (j = 0; j < 3; j++)
960 check[j] = check[j] + omega[
k]*z[j];
962 for (j = 0; j < 3; j++)
963 check[j] = -area2*check[j]/triple;
964 fprintf (stderr,
"(%g,%g,%g) =? (%g,%g,%g)\n",
965 check[X_40],check[Y_40],check[Z_40],
966 vec_omega[X_40],vec_omega[Y_40],vec_omega[Z_40]);
967 for (j = 0; j < 3; j++)
968 check[j] = check[j] - vec_omega[j];
969 rel2 = sqrt(VEC_DOT_40(check,check)/VEC_DOT_40(vec_omega,vec_omega));
970 fprintf (stderr,
"err1 = %g, err2 = %g\n",100*rel1,100*rel2);
977void FwdBemModel::correct_auto_elements(
MneSurfaceOld *surf,
float **mat)
984 int nnode = surf->np;
985 int ntri = surf->ntri;
988 float pi2 = 2.0*M_PI;
992 for (j = 0; j < nnode; j++) {
995 for (
k = 0;
k < nnode;
k++)
997 fprintf (stderr,
"row %d sum = %g missing = %g\n",j+1,sum/pi2,
1002 for (j = 0; j < nnode; j++) {
1008 for (
k = 0;
k < nnode;
k++)
1011 nmemb = surf->nneighbor_tri[j];
1019 miss = miss/(4.0*nmemb);
1020 for (
k = 0,tri = surf->tris;
k < ntri;
k++,tri++) {
1021 if (tri->vert[0] == j) {
1022 row[tri->vert[1]] = row[tri->vert[1]] + miss;
1023 row[tri->vert[2]] = row[tri->vert[2]] + miss;
1025 else if (tri->vert[1] == j) {
1026 row[tri->vert[0]] = row[tri->vert[0]] + miss;
1027 row[tri->vert[2]] = row[tri->vert[2]] + miss;
1029 else if (tri->vert[2] == j) {
1030 row[tri->vert[0]] = row[tri->vert[0]] + miss;
1031 row[tri->vert[1]] = row[tri->vert[1]] + miss;
1048float **FwdBemModel::fwd_bem_lin_pot_coeff(
const QList<MneSurfaceOld*>& surfs)
1054 float **sub_mat = NULL;
1055 int np1,np2,ntri,np_tot,np_max;
1065 for (p = 0, np_tot = np_max = 0; p < surfs.size(); p++) {
1066 np_tot += surfs[p]->np;
1067 if (surfs[p]->np > np_max)
1068 np_max = surfs[p]->np;
1071 mat = ALLOC_CMATRIX_40(np_tot,np_tot);
1072 for (j = 0; j < np_tot; j++)
1073 for (
k = 0;
k < np_tot;
k++)
1075 row = MALLOC_40(np_max,
double);
1076 sub_mat = MALLOC_40(np_max,
float *);
1077 for (p = 0, joff = 0; p < surfs.size(); p++, joff = joff + np1) {
1081 for (q = 0, koff = 0; q < surfs.size(); q++, koff = koff + np2) {
1086 printf(
"\t\t%s (%d) -> %s (%d) ... ",
1087 fwd_bem_explain_surface(surf1->id).toUtf8().constData(),np1,
1088 fwd_bem_explain_surface(surf2->id).toUtf8().constData(),np2);
1090 for (j = 0; j < np1; j++) {
1091 for (
k = 0;
k < np2;
k++)
1093 for (
k = 0, tri = surf2->tris;
k < ntri;
k++,tri++) {
1098 if (p == q && (tri->vert[0] == j || tri->vert[1] == j || tri->vert[2] == j))
1103 lin_pot_coeff (nodes[j],tri,omega);
1104 for (c = 0; c < 3; c++)
1105 row[tri->vert[c]] = row[tri->vert[c]] - omega[c];
1107 for (
k = 0;
k < np2;
k++)
1108 mat[j+joff][
k+koff] = row[
k];
1111 for (j = 0; j < np1; j++)
1112 sub_mat[j] = mat[j+joff]+koff;
1113 correct_auto_elements (surf1,sub_mat);
1125int FwdBemModel::fwd_bem_linear_collocation_solution(
FwdBemModel *m)
1130 float **coeff = NULL;
1137 printf(
"\nComputing the linear collocation solution...\n");
1138 fprintf (stderr,
"\tMatrix coefficients...\n");
1139 if ((coeff = fwd_bem_lin_pot_coeff (m->surfs)) == NULL)
1142 for (
k = 0, m->nsol = 0;
k < m->nsurf;
k++)
1143 m->nsol += m->surfs[
k]->np;
1145 fprintf (stderr,
"\tInverting the coefficient matrix...\n");
1146 if ((m->solution = fwd_bem_multi_solution (coeff,m->gamma,m->nsurf,m->np)) == NULL)
1152 if ((m->nsurf == 3) &&
1153 (ip_mult = m->sigma[m->nsurf-2]/m->sigma[m->nsurf-1]) <= m->ip_approach_limit) {
1154 float **ip_solution = NULL;
1156 fprintf (stderr,
"IP approach required...\n");
1158 fprintf (stderr,
"\tMatrix coefficients (homog)...\n");
1159 QList<MneSurfaceOld*> last_surfs;
1160 last_surfs << m->surfs.last();
1161 if ((coeff = fwd_bem_lin_pot_coeff(last_surfs))== NULL)
1164 fprintf (stderr,
"\tInverting the coefficient matrix (homog)...\n");
1165 if ((ip_solution = fwd_bem_homog_solution (coeff,m->surfs[m->nsurf-1]->np)) == NULL)
1168 fprintf (stderr,
"\tModify the original solution to incorporate IP approach...\n");
1170 fwd_bem_ip_modify_solution(m->solution,ip_solution,ip_mult,m->nsurf,m->np);
1171 FREE_CMATRIX_40(ip_solution);
1174 m->bem_method = FWD_BEM_LINEAR_COLL;
1175 printf(
"Solution ready.\n");
1181 FREE_CMATRIX_40(coeff);
1188float **FwdBemModel::fwd_bem_multi_solution(
float **solids,
float **gamma,
int nsurf,
int *ntri)
1198 float pi2 = 1.0/(2*M_PI);
1200 int joff,koff,jup,kup,ntot;
1202 for (j = 0,ntot = 0; j < nsurf; j++)
1208 for (p = 0, joff = 0; p < nsurf; p++) {
1209 jup = ntri[p] + joff;
1210 for (q = 0, koff = 0; q < nsurf; q++) {
1211 kup = ntri[q] + koff;
1212 mult = (gamma == NULL) ? pi2 : pi2*gamma[p][q];
1213 for (j = joff; j < jup; j++)
1214 for (
k = koff;
k < kup;
k++)
1215 solids[j][
k] = defl - solids[j][
k]*mult;
1220 for (
k = 0;
k < ntot;
k++)
1221 solids[
k][
k] = solids[
k][
k] + 1.0;
1223 return (mne_lu_invert_40(solids,ntot));
1228float **FwdBemModel::fwd_bem_homog_solution(
float **solids,
int ntri)
1236 return fwd_bem_multi_solution (solids,NULL,1,&ntri);
1241void FwdBemModel::fwd_bem_ip_modify_solution(
float **solution,
float **ip_solution,
float ip_mult,
int nsurf,
int *ntri)
1247 int j,
k,joff,koff,ntot,nlast;
1252 for (s = 0, koff = 0; s < nsurf-1; s++)
1253 koff = koff + ntri[s];
1254 nlast = ntri[nsurf-1];
1255 ntot = koff + nlast;
1257 row = MALLOC_40(nlast,
float);
1258 sub = MALLOC_40(ntot,
float *);
1259 mult = (1.0 + ip_mult)/ip_mult;
1261 printf(
"\t\tCombining...");
1264 mne_transpose_square_40(ip_solution,nlast);
1266 for (s = 0, joff = 0; s < nsurf; s++) {
1271 for (j = 0; j < ntri[s]; j++)
1272 sub[j] = solution[j+joff]+koff;
1277 for (j = 0; j < ntri[s]; j++) {
1278 for (
k = 0;
k < nlast;
k++) {
1279 res = mne_dot_vectors_skip_skip(sub[j],1,ip_solution[0]+
k,nlast,nlast);
1280 row[
k] = sub[j][
k] - 2.0*res;
1282 for (
k = 0;
k < nlast;
k++)
1286 for (j = 0; j < ntri[s]; j++) {
1287 for (
k = 0;
k < nlast;
k++)
1288 row[
k] = mne_dot_vectors_40(sub[j],ip_solution[
k],nlast);
1289 mne_add_scaled_vector_to_40(row,-2.0,sub[j],nlast);
1292 joff = joff+ntri[s];
1296 mne_transpose_square_40(ip_solution,nlast);
1302 for (j = 0; j < nlast; j++)
1303 for (
k = 0;
k < nlast;
k++)
1304 sub[j][
k] = sub[j][
k] + mult*ip_solution[j][
k];
1308 printf(
"done.\n\t\tScaling...");
1309 mne_scale_vector_40(ip_mult,solution[0],ntot*ntot);
1311 FREE_40(row); FREE_40(sub);
1317int FwdBemModel::fwd_bem_check_solids(
float **angles,
int ntri1,
int ntri2,
float desired)
1322 float *sums = MALLOC_40(ntri1,
float);
1327 for (j = 0; j < ntri1; j++) {
1329 for (
k = 0;
k < ntri2;
k++)
1330 sum = sum + angles[j][
k];
1331 sums[j] = sum/(2*M_PI);
1333 for (j = 0; j < ntri1; j++)
1340 if (std::fabs(sums[j]-desired) > 1e-4) {
1341 printf(
"solid angle matrix: rowsum[%d] = 2PI*%g",
1352float **FwdBemModel::fwd_bem_solid_angles(
const QList<MneSurfaceOld*>& surfs)
1360 int ntri1,ntri2,ntri_tot;
1365 float **sub_solids = NULL;
1368 for (p = 0,ntri_tot = 0; p < surfs.size(); p++)
1369 ntri_tot += surfs[p]->ntri;
1371 sub_solids = MALLOC_40(ntri_tot,
float *);
1372 solids = ALLOC_CMATRIX_40(ntri_tot,ntri_tot);
1373 for (p = 0, joff = 0; p < surfs.size(); p++, joff = joff + ntri1) {
1375 ntri1 = surf1->ntri;
1376 for (q = 0, koff = 0; q < surfs.size(); q++, koff = koff + ntri2) {
1378 ntri2 = surf2->ntri;
1379 printf(
"\t\t%s (%d) -> %s (%d) ... ",fwd_bem_explain_surface(surf1->id).toUtf8().constData(),ntri1,fwd_bem_explain_surface(surf2->id).toUtf8().constData(),ntri2);
1380 for (j = 0; j < ntri1; j++)
1381 for (
k = 0, tri = surf2->tris;
k < ntri2;
k++, tri++) {
1382 if (p == q && j ==
k)
1385 result = MneSurfaceOrVolume::solid_angle (surf1->tris[j].cent,tri);
1386 solids[j+joff][
k+koff] = result;
1388 for (j = 0; j < ntri1; j++)
1389 sub_solids[j] = solids[j+joff]+koff;
1397 if (fwd_bem_check_solids(sub_solids,ntri1,ntri2,desired) == FAIL) {
1398 FREE_CMATRIX_40(solids);
1399 FREE_40(sub_solids);
1404 FREE_40(sub_solids);
1410int FwdBemModel::fwd_bem_constant_collocation_solution(
FwdBemModel *m)
1415 float **solids = NULL;
1422 printf(
"\nComputing the constant collocation solution...\n");
1423 printf(
"\tSolid angles...\n");
1424 if ((solids = fwd_bem_solid_angles(m->surfs)) == NULL)
1427 for (
k = 0, m->nsol = 0;
k < m->nsurf;
k++)
1428 m->nsol += m->surfs[
k]->ntri;
1430 fprintf (stderr,
"\tInverting the coefficient matrix...\n");
1431 if ((m->solution = fwd_bem_multi_solution (solids,m->gamma,m->nsurf,m->ntri)) == NULL)
1436 if ((m->nsurf == 3) &&
1437 (ip_mult = m->sigma[m->nsurf-2]/m->sigma[m->nsurf-1]) <= m->ip_approach_limit) {
1438 float **ip_solution = NULL;
1440 fprintf (stderr,
"IP approach required...\n");
1442 fprintf (stderr,
"\tSolid angles (homog)...\n");
1443 QList<MneSurfaceOld*> last_surfs;
1444 last_surfs << m->surfs.last();
1445 if ((solids = fwd_bem_solid_angles (last_surfs)) == NULL)
1448 fprintf (stderr,
"\tInverting the coefficient matrix (homog)...\n");
1449 if ((ip_solution = fwd_bem_homog_solution (solids,m->surfs[m->nsurf-1]->ntri)) == NULL)
1452 fprintf (stderr,
"\tModify the original solution to incorporate IP approach...\n");
1453 fwd_bem_ip_modify_solution(m->solution,ip_solution,ip_mult,m->nsurf,m->ntri);
1454 FREE_CMATRIX_40(ip_solution);
1456 m->bem_method = FWD_BEM_CONSTANT_COLL;
1457 fprintf (stderr,
"Solution ready.\n");
1464 FREE_CMATRIX_40(solids);
1471int FwdBemModel::fwd_bem_compute_solution(
FwdBemModel *m,
int bem_method)
1479 if (bem_method == FWD_BEM_LINEAR_COLL)
1480 return fwd_bem_linear_collocation_solution(m);
1481 else if (bem_method == FWD_BEM_CONSTANT_COLL)
1482 return fwd_bem_constant_collocation_solution(m);
1486 printf (
"Unknown BEM method: %d\n",bem_method);
1492int FwdBemModel::fwd_bem_load_recompute_solution(
const QString& name,
int bem_method,
int force_recompute,
FwdBemModel *m)
1500 printf (
"No model specified for fwd_bem_load_recompute_solution");
1504 if (!force_recompute) {
1507 solres = fwd_bem_load_solution(name,bem_method,m);
1508 if (solres == TRUE) {
1509 printf(
"\nLoaded %s BEM solution from %s\n",fwd_bem_explain_method(m->bem_method).toUtf8().constData(),name.toUtf8().constData());
1512 else if (solres == FAIL)
1516 printf(
"Desired BEM solution not available in %s (%s)\n",name,err_get_error());
1519 if (bem_method == FWD_BEM_UNKNOWN)
1520 bem_method = FWD_BEM_LINEAR_COLL;
1521 return fwd_bem_compute_solution(m,bem_method);
1526float FwdBemModel::fwd_bem_inf_field(
float *rd,
float *Q,
float *rp,
float *dir)
1532 float diff[3],diff2,cross[3];
1534 VEC_DIFF_40(rd,rp,diff);
1535 diff2 = VEC_DOT_40(diff,diff);
1536 CROSS_PRODUCT_40(Q,diff,cross);
1538 return (VEC_DOT_40(cross,dir)/(diff2*sqrt(diff2)));
1543float FwdBemModel::fwd_bem_inf_pot(
float *rd,
float *Q,
float *rp)
1550 VEC_DIFF_40(rd,rp,diff);
1551 diff2 = VEC_DOT_40(diff,diff);
1552 return (VEC_DOT_40(Q,diff)/(4.0*M_PI*diff2*sqrt(diff2)));
1565 float *one_sol,*pick_sol;
1566 float r[3],w[3],dist;
1573 printf(
"Model missing in fwd_bem_specify_els");
1577 printf(
"Solution not computed in fwd_bem_specify_els");
1580 if (!els || els->ncoil == 0)
1582 els->fwd_free_coil_set_user_data();
1587 els->user_data_free = FwdBemSolution::fwd_bem_free_coil_solution;
1589 sol->ncoil = els->ncoil;
1591 sol->solution = ALLOC_CMATRIX_40(sol->ncoil,sol->np);
1595 for (
k = 0;
k < els->ncoil;
k++) {
1597 one_sol = sol->solution[
k];
1598 for (q = 0; q < m->nsol; q++)
1600 scalp = m->surfs[0];
1604 for (p = 0; p < el->
np; p++) {
1605 VEC_COPY_40(r,el->
rmag[p]);
1606 if (m->head_mri_t != NULL)
1607 FiffCoordTransOld::fiff_coord_trans(r,m->head_mri_t,FIFFV_MOVE);
1608 best = MneSurfaceOrVolume::mne_project_to_surface(scalp,NULL,r,FALSE,&dist);
1610 printf(
"One of the electrodes could not be projected onto the scalp surface. How come?");
1613 if (m->bem_method == FWD_BEM_CONSTANT_COLL) {
1617 pick_sol = m->solution[best];
1618 for (q = 0; q < m->nsol; q++)
1619 one_sol[q] += el->
w[p]*pick_sol[q];
1621 else if (m->bem_method == FWD_BEM_LINEAR_COLL) {
1625 tri = scalp->tris+best;
1626 MneSurfaceOrVolume::mne_triangle_coords(r,scalp,best,&x,&y,&z);
1628 w[X_40] = el->
w[p]*(1.0 - x - y);
1629 w[Y_40] = el->
w[p]*x;
1630 w[Z_40] = el->
w[p]*y;
1631 for (v = 0; v < 3; v++) {
1632 pick_sol = m->solution[tri->vert[v]];
1633 for (q = 0; q < m->nsol; q++)
1634 one_sol[q] += w[v]*pick_sol[q];
1638 printf(
"Unknown BEM approximation method : %d\n",m->bem_method);
1646 els->fwd_free_coil_set_user_data();
1653void FwdBemModel::fwd_bem_pot_grad_calc(
float *rd,
float *Q,
FwdBemModel* m,
FwdCoilSet* els,
int all_surfs,
float *xgrad,
float *ygrad,
float *zgrad)
1664 float mri_rd[3],mri_Q[3];
1674 m->v0 = MALLOC_40(m->nsol,
float);
1677 VEC_COPY_40(mri_rd,rd);
1678 VEC_COPY_40(mri_Q,Q);
1679 if (m->head_mri_t) {
1680 FiffCoordTransOld::fiff_coord_trans(mri_rd,m->head_mri_t,FIFFV_MOVE);
1681 FiffCoordTransOld::fiff_coord_trans(mri_Q,m->head_mri_t,FIFFV_NO_MOVE);
1683 for (pp = 0; pp < 3; pp++) {
1686 for (p = 0; p < 3; p++)
1687 ee[p] = p == pp ? 1.0 : 0.0;
1689 FiffCoordTransOld::fiff_coord_trans(ee,m->head_mri_t,FIFFV_NO_MOVE);
1691 for (s = 0, p = 0; s < m->nsurf; s++) {
1692 ntri = m->surfs[s]->ntri;
1693 tri = m->surfs[s]->tris;
1694 mult = m->source_mult[s];
1695 for (
k = 0;
k < ntri;
k++, tri++)
1696 v0[p++] = mult*fwd_bem_inf_pot_der(mri_rd,mri_Q,tri->cent,ee);
1700 solution = sol->solution;
1704 solution = m->solution;
1705 nsol = all_surfs ? m->nsol : m->surfs[0]->ntri;
1707 for (
k = 0;
k < nsol;
k++)
1708 grad[
k] = mne_dot_vectors_40(solution[
k],v0,m->nsol);
1715void FwdBemModel::fwd_bem_lin_pot_calc(
float *rd,
float *Q,
FwdBemModel *m,
FwdCoilSet *els,
int all_surfs,
float *pot)
1724 float mult,mri_rd[3],mri_Q[3];
1730 m->v0 = MALLOC_40(m->nsol,
float);
1733 VEC_COPY_40(mri_rd,rd);
1734 VEC_COPY_40(mri_Q,Q);
1735 if (m->head_mri_t) {
1736 FiffCoordTransOld::fiff_coord_trans(mri_rd,m->head_mri_t,FIFFV_MOVE);
1737 FiffCoordTransOld::fiff_coord_trans(mri_Q,m->head_mri_t,FIFFV_NO_MOVE);
1739 for (s = 0, p = 0; s < m->nsurf; s++) {
1740 np = m->surfs[s]->np;
1741 rr = m->surfs[s]->rr;
1742 mult = m->source_mult[s];
1743 for (
k = 0;
k < np;
k++)
1744 v0[p++] = mult*fwd_bem_inf_pot(mri_rd,mri_Q,rr[
k]);
1748 solution = sol->solution;
1752 solution = m->solution;
1753 nsol = all_surfs ? m->nsol : m->surfs[0]->np;
1755 for (
k = 0;
k < nsol;
k++)
1756 pot[
k] = mne_dot_vectors_40(solution[
k],v0,m->nsol);
1762void FwdBemModel::fwd_bem_lin_pot_grad_calc(
float *rd,
float *Q,
FwdBemModel *m,
FwdCoilSet *els,
int all_surfs,
float *xgrad,
float *ygrad,
float *zgrad)
1771 float mult,mri_rd[3],mri_Q[3];
1784 m->v0 = MALLOC_40(m->nsol,
float);
1787 VEC_COPY_40(mri_rd,rd);
1788 VEC_COPY_40(mri_Q,Q);
1789 if (m->head_mri_t) {
1790 FiffCoordTransOld::fiff_coord_trans(mri_rd,m->head_mri_t,FIFFV_MOVE);
1791 FiffCoordTransOld::fiff_coord_trans(mri_Q,m->head_mri_t,FIFFV_NO_MOVE);
1793 for (pp = 0; pp < 3; pp++) {
1796 for (p = 0; p < 3; p++)
1797 ee[p] = p == pp ? 1.0 : 0.0;
1799 FiffCoordTransOld::fiff_coord_trans(ee,m->head_mri_t,FIFFV_NO_MOVE);
1801 for (s = 0, p = 0; s < m->nsurf; s++) {
1802 np = m->surfs[s]->np;
1803 rr = m->surfs[s]->rr;
1804 mult = m->source_mult[s];
1805 for (
k = 0;
k < np;
k++)
1806 v0[p++] = mult*fwd_bem_inf_pot_der(mri_rd,mri_Q,rr[
k],ee);
1810 solution = sol->solution;
1814 solution = m->solution;
1815 nsol = all_surfs ? m->nsol : m->surfs[0]->np;
1817 for (
k = 0;
k < nsol;
k++)
1818 grad[
k] = mne_dot_vectors_40(solution[
k],v0,m->nsol);
1825void FwdBemModel::fwd_bem_pot_calc(
float *rd,
float *Q,
FwdBemModel *m,
FwdCoilSet *els,
int all_surfs,
float *pot)
1836 float mri_rd[3],mri_Q[3];
1839 m->v0 = MALLOC_40(m->nsol,
float);
1842 VEC_COPY_40(mri_rd,rd);
1843 VEC_COPY_40(mri_Q,Q);
1844 if (m->head_mri_t) {
1845 FiffCoordTransOld::fiff_coord_trans(mri_rd,m->head_mri_t,FIFFV_MOVE);
1846 FiffCoordTransOld::fiff_coord_trans(mri_Q,m->head_mri_t,FIFFV_NO_MOVE);
1848 for (s = 0, p = 0; s < m->nsurf; s++) {
1849 ntri = m->surfs[s]->ntri;
1850 tri = m->surfs[s]->tris;
1851 mult = m->source_mult[s];
1852 for (
k = 0;
k < ntri;
k++, tri++)
1853 v0[p++] = mult*fwd_bem_inf_pot(mri_rd,mri_Q,tri->cent);
1857 solution = sol->solution;
1861 solution = m->solution;
1862 nsol = all_surfs ? m->nsol : m->surfs[0]->ntri;
1864 for (
k = 0;
k < nsol;
k++)
1865 pot[
k] = mne_dot_vectors_40(solution[
k],v0,m->nsol);
1871int FwdBemModel::fwd_bem_pot_els(
float *rd,
float *Q,
FwdCoilSet *els,
float *pot,
void *client)
1880 printf(
"No BEM model specified to fwd_bem_pot_els");
1884 printf(
"No solution available for fwd_bem_pot_els");
1887 if (!sol || sol->ncoil != els->ncoil) {
1888 printf(
"No appropriate electrode-specific data available in fwd_bem_pot_coils");
1891 if (m->bem_method == FWD_BEM_CONSTANT_COLL)
1892 fwd_bem_pot_calc(rd,Q,m,els,FALSE,pot);
1893 else if (m->bem_method == FWD_BEM_LINEAR_COLL)
1894 fwd_bem_lin_pot_calc(rd,Q,m,els,FALSE,pot);
1896 printf(
"Unknown BEM method : %d",m->bem_method);
1904int FwdBemModel::fwd_bem_pot_grad_els(
float *rd,
float *Q,
FwdCoilSet *els,
float *pot,
float *xgrad,
float *ygrad,
float *zgrad,
void *client)
1913 qCritical(
"No BEM model specified to fwd_bem_pot_els");
1917 qCritical(
"No solution available for fwd_bem_pot_els");
1920 if (!sol || sol->ncoil != els->ncoil) {
1921 qCritical(
"No appropriate electrode-specific data available in fwd_bem_pot_coils");
1924 if (m->bem_method == FWD_BEM_CONSTANT_COLL) {
1926 fwd_bem_pot_calc(rd,Q,m,els,FALSE,pot);
1927 fwd_bem_pot_grad_calc(rd,Q,m,els,FALSE,xgrad,ygrad,zgrad);
1929 else if (m->bem_method == FWD_BEM_LINEAR_COLL) {
1931 fwd_bem_lin_pot_calc(rd,Q,m,els,FALSE,pot);
1932 fwd_bem_lin_pot_grad_calc(rd,Q,m,els,FALSE,xgrad,ygrad,zgrad);
1935 qCritical(
"Unknown BEM method : %d",m->bem_method);
1943#define ARSINH(x) log((x) + sqrt(1.0+(x)*(x)))
1945void FwdBemModel::calc_f(
double *xx,
double *yy,
double *f0,
double *fx,
double *fy)
1947 double det = -xx[Y_40]*yy[X_40] + xx[Z_40]*yy[X_40] +
1948 xx[X_40]*yy[Y_40] - xx[Z_40]*yy[Y_40] - xx[X_40]*yy[Z_40] + xx[Y_40]*yy[Z_40];
1951 f0[X_40] = -xx[Z_40]*yy[Y_40] + xx[Y_40]*yy[Z_40];
1952 f0[Y_40] = xx[Z_40]*yy[X_40] - xx[X_40]*yy[Z_40];
1953 f0[Z_40] = -xx[Y_40]*yy[X_40] + xx[X_40]*yy[Y_40];
1955 fx[X_40] = yy[Y_40] - yy[Z_40];
1956 fx[Y_40] = -yy[X_40] + yy[Z_40];
1957 fx[Z_40] = yy[X_40] - yy[Y_40];
1959 fy[X_40] = -xx[Y_40] + xx[Z_40];
1960 fy[Y_40] = xx[X_40] - xx[Z_40];
1961 fy[Z_40] = -xx[X_40] + xx[Y_40];
1963 for (
k = 0;
k < 3;
k++) {
1972void FwdBemModel::calc_magic(
double u,
double z,
double A,
double B,
double *beta,
double *D)
1977 double B2 = 1.0 + B*B;
1978 double ABu = A + B*u;
1979 *D = sqrt(u*u + z*z + ABu*ABu);
1980 beta[0] = ABu/sqrt(u*u + z*z);
1981 beta[1] = (A*B + B2*u)/sqrt(A*A + B2*z*z);
1982 beta[2] = (B*z*z - A*u)/(z*(*D));
1987void FwdBemModel::field_integrals(
float *from,
MneTriangle* to,
double *I1p,
double *T,
double *S1,
double *S2,
double *f0,
double *fx,
double *fy)
1989 double y1[3],y2[3],y3[3];
1992 double beta[3],I1,Tx,Ty,Txx,Tyy,Sxx,mult;
1993 double S1x,S1y,S2x,S2y;
2002 VEC_DIFF_40(from,to->r1,y1);
2003 VEC_DIFF_40(from,to->r2,y2);
2004 VEC_DIFF_40(from,to->r3,y3);
2008 xx[0] = VEC_DOT_40(y1,to->ex);
2009 xx[1] = VEC_DOT_40(y2,to->ex);
2010 xx[2] = VEC_DOT_40(y3,to->ex);
2013 yy[0] = VEC_DOT_40(y1,to->ey);
2014 yy[1] = VEC_DOT_40(y2,to->ey);
2015 yy[2] = VEC_DOT_40(y3,to->ey);
2018 calc_f (xx,yy,f0,fx,fy);
2022 z = VEC_DOT_40(y1,to->nn);
2037 for (
k = 0;
k < 2;
k++) {
2038 dx = xx[
k+1] - xx[
k];
2039 A = (yy[
k]*xx[
k+1] - yy[
k+1]*xx[
k])/dx;
2040 B = (yy[
k+1]-yy[
k])/dx;
2045 calc_magic (xx[
k+1],z,A,B,beta,&D1);
2046 I1 = I1 - xx[
k+1]*ARSINH(beta[0]) - (A/sqrt(1.0+B*B))*ARSINH(beta[1])
2048 Txx = ARSINH(beta[1])/sqrt(B2);
2051 Sxx = (D1 - A*B*Txx)/B2;
2054 Sxx = (B*D1 + A*Txx)/B2;
2059 calc_magic (xx[
k],z,A,B,beta,&D1);
2060 I1 = I1 + xx[
k]*ARSINH(beta[0]) + (A/sqrt(1.0+B*B))*ARSINH(beta[1])
2062 Txx = ARSINH(beta[1])/sqrt(B2);
2065 Sxx = (D1 - A*B*Txx)/B2;
2068 Sxx = (B*D1 + A*Txx)/B2;
2074 mult = 1.0/sqrt(xx[
k]*xx[
k]+z*z);
2078 Tyy = ARSINH(mult*yy[
k+1]);
2080 S1y = S1y + xx[
k]*Tyy;
2084 Tyy = ARSINH(mult*yy[
k]);
2086 S1y = S1y - xx[
k]*Tyy;
2102double FwdBemModel::one_field_coeff(
float *dest,
float *normal,
MneTriangle* tri)
2109 double y1[3],y2[3],y3[3];
2119 VEC_DIFF_40(dest,tri->r1,y1);
2120 VEC_DIFF_40(dest,tri->r2,y2);
2121 VEC_DIFF_40(dest,tri->r3,y3);
2122 for (j = 0; j < 3; j++)
2123 beta[j] = calc_beta(yy[j],yy[j+1]);
2124 bbeta[0] = beta[2] - beta[0];
2125 bbeta[1] = beta[0] - beta[1];
2126 bbeta[2] = beta[1] - beta[2];
2128 for (j = 0; j < 3; j++)
2130 for (j = 0; j < 3; j++)
2131 for (
k = 0;
k < 3;
k++)
2132 coeff[
k] = coeff[
k] + yy[j][
k]*bbeta[j];
2133 return (VEC_DOT_40(coeff,normal));
2148 float **coeff = NULL;
2153 if (m->solution == NULL) {
2154 printf(
"Solution matrix missing in fwd_bem_field_coeff");
2157 if (m->bem_method != FWD_BEM_CONSTANT_COLL) {
2158 printf(
"BEM method should be constant collocation for fwd_bem_field_coeff");
2161 if (coils->coord_frame != FIFFV_COORD_MRI) {
2162 if (coils->coord_frame == FIFFV_COORD_HEAD) {
2163 if (!m->head_mri_t) {
2164 printf(
"head -> mri coordinate transform missing in fwd_bem_field_coeff");
2169 qWarning(
"No coils to duplicate");
2175 if ((tcoils = coils->
dup_coil_set(m->head_mri_t)) == NULL)
2181 printf(
"Incompatible coil coordinate frame %d for fwd_bem_field_coeff",coils->coord_frame);
2186 coeff = ALLOC_CMATRIX_40(coils->ncoil,ntri);
2188 for (s = 0, off = 0; s < m->nsurf; s++) {
2192 mult = m->field_mult[s];
2194 for (
k = 0;
k < ntri;
k++,tri++) {
2195 for (j = 0; j < coils->ncoil; j++) {
2196 coil = coils->coils[j];
2198 for (p = 0; p < coil->
np; p++)
2199 res = res + coil->
w[p]*one_field_coeff(coil->
rmag[p],coil->
cosmag[p],tri);
2200 coeff[j][
k+off] = mult*res;
2211double FwdBemModel::calc_gamma(
double *rk,
double *rk1)
2217 VEC_DIFF_40(rk,rk1,rkk1);
2218 size = VEC_LEN_40(rkk1);
2220 res = log((VEC_LEN_40(rk1)*size + VEC_DOT_40(rk1,rkk1))/
2221 (VEC_LEN_40(rk)*size + VEC_DOT_40(rk,rkk1)))/size;
2227void FwdBemModel::fwd_bem_one_lin_field_coeff_ferg(
float *dest,
float *dir,
MneTriangle* tri,
double *res)
2232 double c1[3],c2[3],c3[3];
2233 double y1[3],y2[3],y3[3];
2234 double *yy[4],*cc[4];
2236 double cross[3],triple,l1,l2,l3,solid,clen;
2237 double common,sum,beta,gamma;
2240 yy[0] = y1; cc[0] = c1;
2241 yy[1] = y2; cc[1] = c2;
2242 yy[2] = y3; cc[2] = c3;
2243 yy[3] = y1; cc[3] = c1;
2245 VEC_DIFF_40(tri->r2,tri->r3,rjk[0]);
2246 VEC_DIFF_40(tri->r3,tri->r1,rjk[1]);
2247 VEC_DIFF_40(tri->r1,tri->r2,rjk[2]);
2249 for (
k = 0;
k < 3;
k++) {
2250 y1[
k] = tri->r1[
k] - dest[
k];
2251 y2[
k] = tri->r2[
k] - dest[
k];
2252 y3[
k] = tri->r3[
k] - dest[
k];
2254 clen = VEC_DOT_40(y1,tri->nn);
2255 for (
k = 0;
k < 3;
k++) {
2256 c[
k] = clen*tri->nn[
k];
2257 A[
k] = dest[
k] + c[
k];
2258 c1[
k] = tri->r1[
k] - A[
k];
2259 c2[
k] = tri->r2[
k] - A[
k];
2260 c3[
k] = tri->r3[
k] - A[
k];
2265 for (sum = 0.0,
k = 0;
k < 3;
k++) {
2266 CROSS_PRODUCT_40(cc[
k],cc[
k+1],cross);
2267 beta = VEC_DOT_40(cross,tri->nn);
2268 gamma = calc_gamma (yy[
k],yy[
k+1]);
2269 sum = sum + beta*gamma;
2274 CROSS_PRODUCT_40(y1,y2,cross);
2275 triple = VEC_DOT_40(cross,y3);
2277 l1 = VEC_LEN_40(y1);
2278 l2 = VEC_LEN_40(y2);
2279 l3 = VEC_LEN_40(y3);
2280 solid = 2.0*atan2(triple,
2282 VEC_DOT_40(y1,y2)*l3+
2283 VEC_DOT_40(y1,y3)*l2+
2284 VEC_DOT_40(y2,y3)*l1));
2288 common = (sum-clen*solid)/(2.0*tri->area);
2289 for (
k = 0;
k < 3;
k++)
2290 res[
k] = -VEC_DOT_40(rjk[
k],dir)*common;
2296void FwdBemModel::fwd_bem_one_lin_field_coeff_uran(
float *dest,
float *dir,
MneTriangle* tri,
double *res)
2298 double I1,T[2],S1[2],S2[2];
2299 double f0[3],fx[3],fy[3];
2307 field_integrals (dest,tri,&I1,T,S1,S2,f0,fx,fy);
2311 len = VEC_LEN_40(dir);
2312 dir[X_40] = dir[X_40]/len;
2313 dir[Y_40] = dir[Y_40]/len;
2314 dir[Z_40] = dir[Z_40]/len;
2316 x_fac = -VEC_DOT_40(dir,tri->ex);
2317 y_fac = -VEC_DOT_40(dir,tri->ey);
2318 for (
k = 0;
k < 3;
k++) {
2319 res_x = f0[
k]*T[X_40] + fx[
k]*S1[X_40] + fy[
k]*S2[X_40] + fy[
k]*I1;
2320 res_y = f0[
k]*T[Y_40] + fx[
k]*S1[Y_40] + fy[
k]*S2[Y_40] - fx[
k]*I1;
2321 res[
k] = x_fac*res_x + y_fac*res_y;
2328void FwdBemModel::fwd_bem_one_lin_field_coeff_simple(
float *dest,
float *normal,
MneTriangle* source,
double *res)
2334 float vec_result[3];
2343 for (
k = 0;
k < 3;
k++) {
2344 VEC_DIFF_40(rr[
k],dest,diff);
2345 dl = VEC_DOT_40(diff,diff);
2346 CROSS_PRODUCT_40(diff,source->nn,vec_result);
2347 res[
k] = source->area*VEC_DOT_40(vec_result,normal)/(3.0*dl*sqrt(dl));
2365 float **coeff = NULL;
2367 double res[3],one[3];
2369 linFieldIntFunc func;
2371 if (m->solution == NULL) {
2372 printf(
"Solution matrix missing in fwd_bem_lin_field_coeff");
2375 if (m->bem_method != FWD_BEM_LINEAR_COLL) {
2376 printf(
"BEM method should be linear collocation for fwd_bem_lin_field_coeff");
2379 if (coils->coord_frame != FIFFV_COORD_MRI) {
2380 if (coils->coord_frame == FIFFV_COORD_HEAD) {
2381 if (!m->head_mri_t) {
2382 printf(
"head -> mri coordinate transform missing in fwd_bem_lin_field_coeff");
2387 qWarning(
"No coils to duplicate");
2393 if ((tcoils = coils->
dup_coil_set(m->head_mri_t)) == NULL)
2399 printf(
"Incompatible coil coordinate frame %d for fwd_bem_field_coeff",coils->coord_frame);
2403 if (method == FWD_BEM_LIN_FIELD_FERGUSON)
2404 func = fwd_bem_one_lin_field_coeff_ferg;
2405 else if (method == FWD_BEM_LIN_FIELD_URANKAR)
2406 func = fwd_bem_one_lin_field_coeff_uran;
2408 func = fwd_bem_one_lin_field_coeff_simple;
2410 coeff = ALLOC_CMATRIX_40(coils->ncoil,m->nsol);
2411 for (
k = 0;
k < m->nsol;
k++)
2412 for (j = 0; j < coils->ncoil; j++)
2417 for (s = 0, off = 0; s < m->nsurf; s++) {
2421 mult = m->field_mult[s];
2423 for (
k = 0;
k < ntri;
k++,tri++) {
2424 for (j = 0; j < coils->ncoil; j++) {
2425 coil = coils->coils[j];
2426 for (pp = 0; pp < 3; pp++)
2431 for (p = 0; p < coil->
np; p++) {
2433 for (pp = 0; pp < 3; pp++)
2434 res[pp] = res[pp] + coil->
w[p]*one[pp];
2440 for (pp = 0; pp < 3; pp++)
2441 coeff[j][tri->vert[pp]+off] = coeff[j][tri->vert[pp]+off] + mult*res[pp];
2444 off = off + surf->np;
2464 printf(
"Model missing in fwd_bem_specify_coils");
2468 printf(
"Solution not computed in fwd_bem_specify_coils");
2472 coils->fwd_free_coil_set_user_data();
2473 if (!coils || coils->ncoil == 0)
2475 if (m->bem_method == FWD_BEM_CONSTANT_COLL)
2476 sol = fwd_bem_field_coeff(m,coils);
2477 else if (m->bem_method == FWD_BEM_LINEAR_COLL)
2478 sol = fwd_bem_lin_field_coeff(m,coils,FWD_BEM_LIN_FIELD_SIMPLE);
2480 printf(
"Unknown BEM method in fwd_bem_specify_coils : %d",m->bem_method);
2484 coils->user_data_free = FwdBemSolution::fwd_bem_free_coil_solution;
2486 csol->ncoil = coils->ncoil;
2488 csol->solution = mne_mat_mat_mult_40(sol,
2494 FREE_CMATRIX_40(sol);
2498 FREE_CMATRIX_40(sol);
2506void FwdBemModel::fwd_bem_lin_field_calc(
float *rd,
float *Q,
FwdCoilSet *coils,
FwdBemModel *m,
float *B)
2516 float my_rd[3],my_Q[3];
2522 m->v0 = MALLOC_40(m->nsol,
float);
2527 VEC_COPY_40(my_rd,rd);
2528 VEC_COPY_40(my_Q,Q);
2529 if (m->head_mri_t) {
2530 FiffCoordTransOld::fiff_coord_trans(my_rd,m->head_mri_t,FIFFV_MOVE);
2531 FiffCoordTransOld::fiff_coord_trans(my_Q,m->head_mri_t,FIFFV_NO_MOVE);
2536 for (s = 0, p = 0; s < m->nsurf; s++) {
2537 np = m->surfs[s]->np;
2538 rr = m->surfs[s]->rr;
2539 mult = m->source_mult[s];
2540 for (
k = 0;
k < np;
k++)
2541 v0[p++] = mult*fwd_bem_inf_pot(my_rd,my_Q,rr[
k]);
2547 for (
k = 0;
k < coils->ncoil;
k++) {
2548 coil = coils->coils[
k];
2550 for (p = 0; p < coil->
np; p++)
2551 B[
k] = B[
k] + coil->
w[p]*fwd_bem_inf_field(rd,Q,coil->
rmag[p],coil->
cosmag[p]);
2556 for (
k = 0;
k < coils->ncoil;
k++)
2557 B[
k] = B[
k] + mne_dot_vectors_40(sol->solution[
k],v0,m->nsol);
2561 for (
k = 0;
k < coils->ncoil;
k++)
2562 B[
k] = MAG_FACTOR*B[
k];
2568void FwdBemModel::fwd_bem_field_calc(
float *rd,
float *Q,
FwdCoilSet *coils,
FwdBemModel *m,
float *B)
2578 float my_rd[3],my_Q[3];
2584 m->v0 = MALLOC_40(m->nsol,
float);
2589 VEC_COPY_40(my_rd,rd);
2590 VEC_COPY_40(my_Q,Q);
2591 if (m->head_mri_t) {
2592 FiffCoordTransOld::fiff_coord_trans(my_rd,m->head_mri_t,FIFFV_MOVE);
2593 FiffCoordTransOld::fiff_coord_trans(my_Q,m->head_mri_t,FIFFV_NO_MOVE);
2598 for (s = 0, p = 0; s < m->nsurf; s++) {
2599 ntri = m->surfs[s]->ntri;
2600 tri = m->surfs[s]->tris;
2601 mult = m->source_mult[s];
2602 for (
k = 0;
k < ntri;
k++, tri++)
2603 v0[p++] = mult*fwd_bem_inf_pot(my_rd,my_Q,tri->cent);
2609 for (
k = 0;
k < coils->ncoil;
k++) {
2610 coil = coils->coils[
k];
2612 for (p = 0; p < coil->
np; p++)
2613 B[
k] = B[
k] + coil->
w[p]*fwd_bem_inf_field(rd,Q,coil->
rmag[p],coil->
cosmag[p]);
2618 for (
k = 0;
k < coils->ncoil;
k++)
2619 B[
k] = B[
k] + mne_dot_vectors_40(sol->solution[
k],v0,m->nsol);
2623 for (
k = 0;
k < coils->ncoil;
k++)
2624 B[
k] = MAG_FACTOR*B[
k];
2630void FwdBemModel::fwd_bem_field_grad_calc(
float *rd,
float *Q,
FwdCoilSet* coils,
FwdBemModel* m,
float *xgrad,
float *ygrad,
float *zgrad)
2641 float *grads[3],ee[3],mri_ee[3],mri_rd[3],mri_Q[3];
2651 m->v0 = MALLOC_40(m->nsol,
float);
2656 VEC_COPY_40(mri_rd,rd);
2657 VEC_COPY_40(mri_Q,Q);
2658 if (m->head_mri_t) {
2659 FiffCoordTransOld::fiff_coord_trans(mri_rd,m->head_mri_t,FIFFV_MOVE);
2660 FiffCoordTransOld::fiff_coord_trans(mri_Q,m->head_mri_t,FIFFV_NO_MOVE);
2662 for (pp = 0; pp < 3; pp++) {
2667 for (p = 0; p < 3; p++)
2668 ee[p] = p == pp ? 1.0 : 0.0;
2669 VEC_COPY_40(mri_ee,ee);
2671 FiffCoordTransOld::fiff_coord_trans(mri_ee,m->head_mri_t,FIFFV_NO_MOVE);
2675 for (s = 0, p = 0; s < m->nsurf; s++) {
2676 ntri = m->surfs[s]->ntri;
2677 tri = m->surfs[s]->tris;
2678 mult = m->source_mult[s];
2679 for (
k = 0;
k < ntri;
k++, tri++) {
2680 v0[p++] = mult*fwd_bem_inf_pot_der(mri_rd,mri_Q,tri->cent,mri_ee);
2687 for (
k = 0;
k < coils->ncoil;
k++) {
2688 coil = coils->coils[
k];
2690 for (p = 0; p < coil->
np; p++)
2691 grad[
k] = grad[
k] + coil->
w[p]*fwd_bem_inf_field_der(rd,Q,coil->
rmag[p],coil->
cosmag[p],ee);
2696 for (
k = 0;
k < coils->ncoil;
k++)
2697 grad[
k] = grad[
k] + mne_dot_vectors_40(sol->solution[
k],v0,m->nsol);
2701 for (
k = 0;
k < coils->ncoil;
k++)
2702 grad[
k] = MAG_FACTOR*grad[
k];
2709float FwdBemModel::fwd_bem_inf_field_der(
float *rd,
float *Q,
float *rp,
float *dir,
float *comp)
2715 float diff[3],diff2,diff3,diff5,cross[3],crossn[3],res;
2717 VEC_DIFF_40(rd,rp,diff);
2718 diff2 = VEC_DOT_40(diff,diff);
2719 diff3 = sqrt(diff2)*diff2;
2720 diff5 = diff3*diff2;
2721 CROSS_PRODUCT_40(Q,diff,cross);
2722 CROSS_PRODUCT_40(dir,Q,crossn);
2724 res = 3*VEC_DOT_40(cross,dir)*VEC_DOT_40(comp,diff)/diff5 - VEC_DOT_40(comp,crossn)/diff3;
2730float FwdBemModel::fwd_bem_inf_pot_der(
float *rd,
float *Q,
float *rp,
float *comp)
2737 float diff2,diff5,diff3;
2740 VEC_DIFF_40(rd,rp,diff);
2741 diff2 = VEC_DOT_40(diff,diff);
2742 diff3 = sqrt(diff2)*diff2;
2743 diff5 = diff3*diff2;
2745 res = 3*VEC_DOT_40(Q,diff)*VEC_DOT_40(comp,diff)/diff5 - VEC_DOT_40(comp,Q)/diff3;
2746 return (res/(4.0*M_PI));
2751void FwdBemModel::fwd_bem_lin_field_grad_calc(
float *rd,
float *Q,
FwdCoilSet *coils,
FwdBemModel *m,
float *xgrad,
float *ygrad,
float *zgrad)
2762 float **rr,ee[3],mri_ee[3],mri_rd[3],mri_Q[3];
2773 m->v0 = MALLOC_40(m->nsol,
float);
2778 VEC_COPY_40(mri_rd,rd);
2779 VEC_COPY_40(mri_Q,Q);
2780 if (m->head_mri_t) {
2781 FiffCoordTransOld::fiff_coord_trans(mri_rd,m->head_mri_t,FIFFV_MOVE);
2782 FiffCoordTransOld::fiff_coord_trans(mri_Q,m->head_mri_t,FIFFV_NO_MOVE);
2784 for (pp = 0; pp < 3; pp++) {
2789 for (p = 0; p < 3; p++)
2790 ee[p] = p == pp ? 1.0 : 0.0;
2791 VEC_COPY_40(mri_ee,ee);
2793 FiffCoordTransOld::fiff_coord_trans(mri_ee,m->head_mri_t,FIFFV_NO_MOVE);
2797 for (s = 0, p = 0; s < m->nsurf; s++) {
2798 np = m->surfs[s]->np;
2799 rr = m->surfs[s]->rr;
2800 mult = m->source_mult[s];
2802 for (
k = 0;
k < np;
k++)
2803 v0[p++] = mult*fwd_bem_inf_pot_der(mri_rd,mri_Q,rr[
k],mri_ee);
2809 for (
k = 0;
k < coils->ncoil;
k++) {
2810 coil = coils->coils[
k];
2812 for (p = 0; p < coil->
np; p++)
2813 grad[
k] = grad[
k] + coil->
w[p]*fwd_bem_inf_field_der(rd,Q,coil->
rmag[p],coil->
cosmag[p],ee);
2818 for (
k = 0;
k < coils->ncoil;
k++)
2819 grad[
k] = grad[
k] + mne_dot_vectors_40(sol->solution[
k],v0,m->nsol);
2823 for (
k = 0;
k < coils->ncoil;
k++)
2824 grad[
k] = MAG_FACTOR*grad[
k];
2831int FwdBemModel::fwd_bem_field(
float *rd,
float *Q,
FwdCoilSet *coils,
float *B,
void *client)
2842 printf(
"No BEM model specified to fwd_bem_field");
2845 if (!sol || !sol->solution || sol->ncoil != coils->ncoil) {
2846 printf(
"No appropriate coil-specific data available in fwd_bem_field");
2849 if (m->bem_method == FWD_BEM_CONSTANT_COLL)
2850 fwd_bem_field_calc(rd,Q,coils,m,B);
2851 else if (m->bem_method == FWD_BEM_LINEAR_COLL)
2852 fwd_bem_lin_field_calc(rd,Q,coils,m,B);
2854 printf(
"Unknown BEM method : %d",m->bem_method);
2862int FwdBemModel::fwd_bem_field_grad(
float *rd,
2875 qCritical(
"No BEM model specified to fwd_bem_field");
2879 if (!sol || !sol->solution || sol->ncoil != coils->ncoil) {
2880 qCritical(
"No appropriate coil-specific data available in fwd_bem_field");
2884 if (m->bem_method == FWD_BEM_CONSTANT_COLL) {
2886 fwd_bem_field_calc(rd,
2893 fwd_bem_field_grad_calc(rd,
2900 }
else if (m->bem_method == FWD_BEM_LINEAR_COLL) {
2902 fwd_bem_lin_field_calc(rd,
2909 fwd_bem_lin_field_grad_calc(rd,
2917 qCritical(
"Unknown BEM method : %d",m->bem_method);
2926void *FwdBemModel::meg_eeg_fwd_one_source_space(
void *arg)
2940 if (a->field_pot_grad && a->res_grad) {
2941 for (j = 0; j < s->np; j++) {
2943 if (a->field_pot_grad(s->rr[j],
2958 for (j = 0; j < s->np; j++)
2960 if (a->field_pot(s->rr[j],
2969 if (a->field_pot_grad && a->res_grad) {
2970 for (j = 0; j < s->np; j++) {
2973 if (a->field_pot_grad(s->rr[j],
2983 if (a->field_pot_grad(s->rr[j],
2993 if (a->field_pot_grad(s->rr[j],
3004 else if (a->comp == 0) {
3005 if (a->field_pot_grad(s->rr[j],
3018 else if (a->comp == 1) {
3020 if (a->field_pot_grad(s->rr[j],
3032 else if (a->comp == 2) {
3035 if (a->field_pot_grad(s->rr[j],
3050 for (j = 0; j < s->np; j++) {
3052 if (a->vec_field_pot) {
3053 xyz[0] = a->res[p++];
3054 xyz[1] = a->res[p++];
3055 xyz[2] = a->res[p++];
3056 if (a->vec_field_pot(s->rr[j],a->coils_els,xyz,a->client) != OK)
3061 if (a->field_pot(s->rr[j],Qx,a->coils_els,a->res[p++],a->client) != OK)
3063 if (a->field_pot(s->rr[j],Qy,a->coils_els,a->res[p++],a->client) != OK)
3065 if (a->field_pot(s->rr[j],Qz,a->coils_els,a->res[p++],a->client) != OK)
3068 else if (a->comp == 0) {
3069 if (a->field_pot(s->rr[j],Qx,a->coils_els,a->res[p++],a->client) != OK)
3073 else if (a->comp == 1) {
3075 if (a->field_pot(s->rr[j],Qy,a->coils_els,a->res[p++],a->client) != OK)
3079 else if (a->comp == 2) {
3081 if (a->field_pot(s->rr[j],Qz,a->coils_els,a->res[p++],a->client) != OK)
3118 float **res_grad = NULL;
3120 MatrixXd matResGrad;
3124 fwdVecFieldFunc vec_field;
3125 fwdFieldGradFunc field_grad;
3127 int nmeg = coils->ncoil;
3133 int nproc = QThread::idealThreadCount();
3134 QStringList emptyList;
3142 printf(
"Using differences.\n");
3143 comp = FwdCompData::fwd_make_comp_data(comp_data,
3145 FwdBemModel::fwd_bem_field,
3151 comp = FwdCompData::fwd_make_comp_data(comp_data,
3154 FwdBemModel::fwd_bem_field,
3156 FwdBemModel::fwd_bem_field_grad,
3165 qDebug() <<
"!!!TODO Speed the following with Eigen up!";
3166 printf(
"Composing the field computation matrix...");
3167 if (fwd_bem_specify_coils(bem_model,coils) == FAIL)
3171 if (comp->set && comp->set->current) {
3172 printf(
"Composing the field computation matrix (compensation coils)...");
3173 if (fwd_bem_specify_coils(bem_model,comp->comp_coils) == FAIL)
3177 field = FwdCompData::fwd_comp_field;
3179 field_grad = FwdCompData::fwd_comp_field_grad;
3188 printf(
"Using differences.\n");
3189 comp = FwdCompData::fwd_make_comp_data(comp_data,coils,comp_coils,
3191 fwd_sphere_field_vec,
3192 my_sphere_field_grad,
3195 comp = FwdCompData::fwd_make_comp_data(comp_data,coils,comp_coils,
3197 fwd_sphere_field_vec,
3198 fwd_sphere_field_grad,
3203 field = FwdCompData::fwd_comp_field;
3204 vec_field = FwdCompData::fwd_comp_field_vec;
3205 field_grad = FwdCompData::fwd_comp_field_grad;
3211 for (
k = 0, nsource = 0;
k < nspace;
k++)
3212 nsource += spaces[
k]->nuse;
3217 res = ALLOC_CMATRIX_40(nsource,nmeg);
3219 res = ALLOC_CMATRIX_40(3*nsource,nmeg);
3222 res_grad = ALLOC_CMATRIX_40(3*nsource,nmeg);
3224 res_grad = ALLOC_CMATRIX_40(3*3*nsource,nmeg);
3231 one_arg->res_grad = res_grad;
3233 one_arg->coils_els = coils;
3234 one_arg->client = client;
3236 one_arg->fixed_ori = fixed_ori;
3237 one_arg->field_pot = field;
3238 one_arg->vec_field_pot = vec_field;
3239 one_arg->field_pot_grad = field_grad;
3242 use_threads =
false;
3245 int nthread = (fixed_ori || vec_field || nproc < 6) ? nspace : 3*nspace;
3246 QList <FwdThreadArg*> args;
3251 if (fixed_ori || vec_field || nproc < 6) {
3252 for (
k = 0, off = 0;
k < nthread;
k++) {
3253 FwdThreadArg* t_arg = FwdThreadArg::create_meg_multi_thread_duplicate(one_arg,bem_model != NULL);
3254 t_arg->s = spaces[
k];
3256 off = fixed_ori ? off + spaces[
k]->nuse : off + 3*spaces[
k]->nuse;
3259 printf(
"%d processors. I will use one thread for each of the %d source spaces.\n",
3263 for (
k = 0, off = 0, q = 0;
k < nspace;
k++) {
3264 for (p = 0; p < 3; p++,q++) {
3265 FwdThreadArg* t_arg = FwdThreadArg::create_meg_multi_thread_duplicate(one_arg,bem_model != NULL);
3266 t_arg->s = spaces[
k];
3271 off = fixed_ori ? off + spaces[
k]->nuse : off + 3*spaces[
k]->nuse;
3273 printf(
"%d processors. I will use %d threads : %d source spaces x 3 source components.\n",
3274 nproc,nthread,nspace);
3276 printf(
"Computing MEG at %d source locations (%s orientations)...",
3277 nsource,fixed_ori ?
"fixed" :
"free");
3281 QtConcurrent::blockingMap(args, meg_eeg_fwd_one_source_space);
3285 for (
k = 0, stat = OK;
k < nthread;
k++)
3286 if (args[
k]->stat != OK) {
3290 for (
k = 0;
k < args.size();
k++)
3291 FwdThreadArg::free_meg_multi_thread_duplicate(args[
k],bem_model != NULL);
3296 printf(
"Computing MEG at %d source locations (%s orientations, no threads)...",
3297 nsource,fixed_ori ?
"fixed" :
"free");
3298 for (
k = 0, off = 0;
k < nspace;
k++) {
3299 one_arg->s = spaces[
k];
3301 meg_eeg_fwd_one_source_space(one_arg);
3302 if (one_arg->stat != OK)
3304 off = fixed_ori ? off + one_arg->s->nuse : off + 3*one_arg->s->nuse;
3309 QStringList orig_names;
3310 for (
k = 0;
k < nmeg;
k++)
3311 orig_names.append(coils->coils[
k]->
chname);
3320 nrow = fixed_ori ? nsource : 3*nsource;
3321 matRes.conservativeResize(nrow,nmeg);
3322 for(
int i = 0; i < nrow; i++) {
3323 for(
int j = 0; j < nmeg; j++) {
3324 matRes(i,j) = res[i][j];
3334 if (bDoGrad && res_grad) {
3335 nrow = fixed_ori ? 3*nsource : 3*3*nsource;
3336 matResGrad = MatrixXd::Zero(nrow,nmeg);
3337 for(
int i = 0; i < nrow; i++) {
3338 for(
int j = 0; j < nmeg; j++) {
3339 matResGrad(i,j) = res_grad[i][j];
3342 resp_grad.
nrow = nrow;
3343 resp_grad.
ncol = nmeg;
3346 resp_grad.
data = matResGrad;
3356 FREE_CMATRIX_40(res);
3357 FREE_CMATRIX_40(res_grad);
3380 float **res_grad = NULL;
3382 MatrixXd matResGrad;
3385 fwdVecFieldFunc vec_pot;
3386 fwdFieldGradFunc pot_grad;
3389 int neeg = els->ncoil;
3394 int nproc = QThread::idealThreadCount();
3395 QStringList emptyList;
3399 for (
k = 0, nsource = 0;
k < nspace;
k++)
3400 nsource += spaces[
k]->nuse;
3403 if (fwd_bem_specify_els(bem_model,els) == FAIL)
3406 pot = fwd_bem_pot_els;
3409 printf(
"Using differences.\n");
3410 pot_grad = my_bem_pot_grad;
3412 pot_grad = fwd_bem_pot_grad_els;
3417 printf(
"Using the standard series expansion for a multilayer sphere model for EEG\n");
3418 pot = FwdEegSphereModel::fwd_eeg_multi_spherepot_coil1;
3423 printf(
"Using the equivalent source approach in the homogeneous sphere for EEG\n");
3426 pot_grad = FwdEegSphereModel::fwd_eeg_spherepot_grad_coil;
3434 res = ALLOC_CMATRIX_40(nsource,neeg);
3436 res = ALLOC_CMATRIX_40(3*nsource,neeg);
3439 qCritical(
"EEG gradient calculation function not available");
3443 res_grad = ALLOC_CMATRIX_40(3*nsource,neeg);
3445 res_grad = ALLOC_CMATRIX_40(3*3*nsource,neeg);
3452 one_arg->res_grad = res_grad;
3454 one_arg->coils_els = els;
3455 one_arg->client = client;
3457 one_arg->fixed_ori = fixed_ori;
3458 one_arg->field_pot = pot;
3459 one_arg->vec_field_pot = vec_pot;
3460 one_arg->field_pot_grad = pot_grad;
3463 use_threads =
false;
3466 int nthread = (fixed_ori || vec_pot || nproc < 6) ? nspace : 3*nspace;
3467 QList <FwdThreadArg*> args;
3472 if (fixed_ori || vec_pot || nproc < 6) {
3473 for (
k = 0, off = 0;
k < nthread;
k++) {
3474 FwdThreadArg* t_arg = FwdThreadArg::create_eeg_multi_thread_duplicate(one_arg,bem_model != NULL);
3475 t_arg->s = spaces[
k];
3477 off = fixed_ori ? off + spaces[
k]->nuse : off + 3*spaces[
k]->nuse;
3480 printf(
"%d processors. I will use one thread for each of the %d source spaces.\n",nproc,nspace);
3483 for (
k = 0, off = 0, q = 0;
k < nspace;
k++) {
3484 for (p = 0; p < 3; p++,q++) {
3485 FwdThreadArg* t_arg = FwdThreadArg::create_eeg_multi_thread_duplicate(one_arg,bem_model != NULL);
3486 t_arg->s = spaces[
k];
3491 off = fixed_ori ? off + spaces[
k]->nuse : off + 3*spaces[
k]->nuse;
3493 printf(
"%d processors. I will use %d threads : %d source spaces x 3 source components.\n",nproc,nthread,nspace);
3495 printf(
"Computing EEG at %d source locations (%s orientations)...",
3496 nsource,fixed_ori ?
"fixed" :
"free");
3500 QtConcurrent::blockingMap(args, meg_eeg_fwd_one_source_space);
3504 for (
k = 0, stat = OK;
k < nthread;
k++)
3505 if (args[
k]->stat != OK) {
3509 for (
k = 0;
k < args.size();
k++)
3510 FwdThreadArg::free_eeg_multi_thread_duplicate(args[
k],bem_model != NULL);
3515 printf(
"Computing EEG at %d source locations (%s orientations, no threads)...",
3516 nsource,fixed_ori ?
"fixed" :
"free");
3517 for (
k = 0, off = 0;
k < nspace;
k++) {
3518 one_arg->s = spaces[
k];
3520 meg_eeg_fwd_one_source_space(one_arg);
3521 if (one_arg->stat != OK)
3523 off = fixed_ori ? off + one_arg->s->nuse : off + 3*one_arg->s->nuse;
3528 QStringList orig_names;
3529 for (
k = 0;
k < neeg;
k++)
3530 orig_names.append(els->coils[
k]->
chname);
3537 nrow = fixed_ori ? nsource : 3*nsource;
3538 matRes.conservativeResize(nrow,neeg);
3539 for(
int i = 0; i < nrow; i++) {
3540 for(
int j = 0; j < neeg; j++) {
3541 matRes(i,j) = res[i][j];
3551 if (bDoGrad && res_grad) {
3552 matResGrad = MatrixXd::Zero(fixed_ori ? 3*nsource : 3*3*nsource,neeg);
3553 for(
int i = 0; i < nrow; i++) {
3554 for(
int j = 0; j < neeg; j++) {
3555 matResGrad(i,j) = res_grad[i][j];
3558 resp_grad.
nrow = nrow;
3559 resp_grad.
ncol = neeg;
3562 resp_grad.
data = matResGrad;
3570 FREE_CMATRIX_40(res);
3571 FREE_CMATRIX_40(res_grad);
3583int FwdBemModel::fwd_sphere_field(
float *rd,
float Q[],
FwdCoilSet *coils,
float Bval[],
void *client)
3599 float *r0 = (
float *)client;
3600 float v[3],a_vec[3];
3604 float F,g0,gr,result,sum;
3607 float *this_pos,*this_dir;
3614 for (p = 0; p < 3; p++)
3615 myrd[p] = rd[p] - r0[p];
3620 for (
k = 0 ;
k < coils->ncoil ;
k++)
3626 CROSS_PRODUCT_40(Q,rd,v);
3628 for (
k = 0;
k < coils->ncoil;
k++) {
3629 this_coil = coils->coils[
k];
3630 if (FWD_IS_MEG_COIL(this_coil->
type)) {
3634 for (j = 0, sum = 0.0; j < np; j++) {
3636 this_pos = this_coil->
rmag[j];
3637 this_dir = this_coil->
cosmag[j];
3639 for (p = 0; p < 3; p++)
3640 pos[p] = this_pos[p] - r0[p];
3646 VEC_DIFF_40(rd,this_pos,a_vec);
3650 a2 = VEC_DOT_40(a_vec,a_vec); a = sqrt(a2);
3653 r2 = VEC_DOT_40(this_pos,this_pos); r = sqrt(r2);
3655 rr0 = VEC_DOT_40(this_pos,rd);
3657 if (std::fabs(ar/(a*r)+1.0) > CEPS) {
3661 ve = VEC_DOT_40(v,this_dir); vr = VEC_DOT_40(v,this_pos);
3662 re = VEC_DOT_40(this_pos,this_dir); r0e = VEC_DOT_40(rd,this_dir);
3667 gr = a2/r + ar0 + 2.0*(a+r);
3672 sum = sum + this_coil->
w[j]*(ve*F + vr*(g0*r0e - gr*re))/(F*F);
3677 Bval[
k] = MAG_FACTOR*sum;
3686int FwdBemModel::fwd_sphere_field_vec(
float *rd,
FwdCoilSet *coils,
float **Bval,
void *client)
3708 float *r0 = (
float *)client;
3709 float a_vec[3],v1[3],v2[3];
3713 float F,g0,gr,g,sum[3];
3716 float *this_pos,*this_dir;
3723 for (p = 0; p < 3; p++)
3724 myrd[p] = rd[p] - r0[p];
3730 for (
k = 0;
k < coils->ncoil;
k++) {
3731 this_coil = coils->coils[
k];
3732 if (FWD_IS_MEG_COIL(this_coil->
coil_class)) {
3734 Bval[0][
k] = Bval[1][
k] = Bval[2][
k] = 0.0;
3739 sum[0] = sum[1] = sum[2] = 0.0;
3741 for (j = 0; j < np; j++) {
3743 this_pos = this_coil->
rmag[j];
3744 this_dir = this_coil->
cosmag[j];
3746 for (p = 0; p < 3; p++)
3747 pos[p] = this_pos[p] - r0[p];
3752 VEC_DIFF_40(rd,this_pos,a_vec);
3756 a2 = VEC_DOT_40(a_vec,a_vec); a = sqrt(a2);
3759 r2 = VEC_DOT_40(this_pos,this_pos); r = sqrt(r2);
3761 rr0 = VEC_DOT_40(this_pos,rd);
3763 if (std::fabs(ar/(a*r)+1.0) > CEPS) {
3770 gr = a2/r + ar0 + 2.0*(a+r);
3773 re = VEC_DOT_40(this_pos,this_dir); r0e = VEC_DOT_40(rd,this_dir);
3774 CROSS_PRODUCT_40(rd,this_dir,v1);
3775 CROSS_PRODUCT_40(rd,this_pos,v2);
3777 g = (g0*r0e - gr*re)/(F*F);
3781 for (p = 0; p < 3; p++)
3782 sum[p] = sum[p] + this_coil->
w[j]*(v1[p]/F + v2[p]*g);
3787 for (p = 0; p < 3; p++)
3788 Bval[p][
k] = MAG_FACTOR*sum[p];
3797int FwdBemModel::fwd_sphere_field_grad(
float *rd,
float Q[],
FwdCoilSet *coils,
float Bval[],
float xgrad[],
float ygrad[],
float zgrad[],
void *client)
3818 float v[3],a_vec[3];
3822 float F,g0,gr,result,G,F2;
3826 float ggr[3],gg0[3];
3834 float *this_pos,*this_dir;
3838 float *r0 = (
float *)client;
3842 for (p = 0; p < 3; p++)
3843 myrd[p] = rd[p] - r0[p];
3852 for (
k = 0;
k < coils->ncoil ;
k++) {
3853 if (FWD_IS_MEG_COIL(coils->coils[
k]->
coil_class)) {
3863 v[X_40] = Q[Y_40]*rd[Z_40] - Q[Z_40]*rd[Y_40];
3864 v[Y_40] = -Q[X_40]*rd[Z_40] + Q[Z_40]*rd[X_40];
3865 v[Z_40] = Q[X_40]*rd[Y_40] - Q[Y_40]*rd[X_40];
3867 for (
k = 0 ;
k < coils->ncoil ;
k++) {
3869 this_coil = coils->coils[
k];
3871 if (FWD_IS_MEG_COIL(this_coil->
type)) {
3875 for (j = 0; j < np; j++) {
3877 this_pos = this_coil->
rmag[j];
3881 for (p = 0; p < 3; p++)
3882 pos[p] = this_pos[p] - r0[p];
3885 this_dir = this_coil->
cosmag[j];
3889 a_vec[X_40] = this_pos[X_40] - rd[X_40];
3890 a_vec[Y_40] = this_pos[Y_40] - rd[Y_40];
3891 a_vec[Z_40] = this_pos[Z_40] - rd[Z_40];
3895 a2 = VEC_DOT_40(a_vec,a_vec); a = sqrt(a2);
3896 r2 = VEC_DOT_40(this_pos,this_pos); r = sqrt(r2);
3897 rr0 = VEC_DOT_40(this_pos,rd);
3900 ve = VEC_DOT_40(v,this_dir); vr = VEC_DOT_40(v,this_pos);
3901 re = VEC_DOT_40(this_pos,this_dir); r0e = VEC_DOT_40(rd,this_dir);
3905 eQ[X_40] = this_dir[Y_40]*Q[Z_40] - this_dir[Z_40]*Q[Y_40];
3906 eQ[Y_40] = -this_dir[X_40]*Q[Z_40] + this_dir[Z_40]*Q[X_40];
3907 eQ[Z_40] = this_dir[X_40]*Q[Y_40] - this_dir[Y_40]*Q[X_40];
3911 rQ[X_40] = this_pos[Y_40]*Q[Z_40] - this_pos[Z_40]*Q[Y_40];
3912 rQ[Y_40] = -this_pos[X_40]*Q[Z_40] + this_pos[Z_40]*Q[X_40];
3913 rQ[Z_40] = this_pos[X_40]*Q[Y_40] - this_pos[Y_40]*Q[X_40];
3917 F = a*(r*a + r2 - rr0);
3919 gr = a2/r + ar + 2.0*(a+r);
3920 g0 = a + 2.0*r + ar;
3925 result = (ve*F + vr*G)/F2;
3929 huu = 2.0 + 2.0*a/r;
3930 for (p = X_40; p <= Z_40; p++) {
3931 ga[p] = -a_vec[p]/a;
3932 gar[p] = -(ga[p]*ar + this_pos[p])/a;
3933 gg0[p] = ga[p] + gar[p];
3934 ggr[p] = huu*ga[p] + gar[p];
3935 gFF[p] = ga[p]/a - (r*a_vec[p] + a*this_pos[p])/F;
3936 gresult[p] = -2.0*result*gFF[p] + (eQ[p]+gFF[p]*ve)/F +
3937 (rQ[p]*G + vr*(gg0[p]*r0e + g0*this_dir[p] - ggr[p]*re))/F2;
3941 Bval[
k] = Bval[
k] + this_coil->
w[j]*result;
3942 xgrad[
k] = xgrad[
k] + this_coil->
w[j]*gresult[X_40];
3943 ygrad[
k] = ygrad[
k] + this_coil->
w[j]*gresult[Y_40];
3944 zgrad[
k] = zgrad[
k] + this_coil->
w[j]*gresult[Z_40];
3947 Bval[
k] = MAG_FACTOR*Bval[
k];
3948 xgrad[
k] = MAG_FACTOR*xgrad[
k];
3949 ygrad[
k] = MAG_FACTOR*ygrad[
k];
3950 zgrad[
k] = MAG_FACTOR*zgrad[
k];
3959int FwdBemModel::fwd_mag_dipole_field(
float *rm,
float M[],
FwdCoilSet *coils,
float Bval[],
void *client)
3966 float sum,diff[3],dist,dist2,dist5,*dir;
3968 for (
k = 0;
k < coils->ncoil;
k++) {
3969 this_coil = coils->coils[
k];
3970 if (FWD_IS_MEG_COIL(this_coil->
type)) {
3975 for (j = 0, sum = 0.0; j < np; j++) {
3976 dir = this_coil->
cosmag[j];
3977 VEC_DIFF_40(rm,this_coil->
rmag[j],diff);
3978 dist = VEC_LEN_40(diff);
3981 dist5 = dist2*dist2*dist;
3982 sum = sum + this_coil->
w[j]*(3*VEC_DOT_40(M,diff)*VEC_DOT_40(diff,dir) - dist2*VEC_DOT_40(M,dir))/dist5;
3985 Bval[
k] = MAG_FACTOR*sum;
3987 else if (this_coil->
type == FWD_COILC_EEG)
3995int FwdBemModel::fwd_mag_dipole_field_vec(
float *rm,
FwdCoilSet *coils,
float **Bval,
void *client)
4003 float sum[3],diff[3],dist,dist2,dist5,*dir;
4005 for (
k = 0;
k < coils->ncoil;
k++) {
4006 this_coil = coils->coils[
k];
4007 if (FWD_IS_MEG_COIL(this_coil->
type)) {
4009 sum[0] = sum[1] = sum[2] = 0.0;
4013 for (j = 0; j < np; j++) {
4014 dir = this_coil->
cosmag[j];
4015 VEC_DIFF_40(rm,this_coil->
rmag[j],diff);
4016 dist = VEC_LEN_40(diff);
4019 dist5 = dist2*dist2*dist;
4020 for (p = 0; p < 3; p++)
4021 sum[p] = sum[p] + this_coil->
w[j]*(3*diff[p]*VEC_DOT_40(diff,dir) - dist2*dir[p])/dist5;
4024 for (p = 0; p < 3; p++)
4025 Bval[p][
k] = MAG_FACTOR*sum[p];
4027 else if (this_coil->
type == FWD_COILC_EEG) {
4028 for (p = 0; p < 3; p++)
#define FIFFV_MNE_COORD_MNI_TAL
#define FIFFV_MNE_COORD_FS_TAL_LTZ
#define FIFFV_MNE_COORD_CTF_DEVICE
#define FIFFV_MNE_COORD_MRI_VOXEL
#define FIFFV_MNE_COORD_CTF_HEAD
#define FIFFV_MNE_COORD_FS_TAL_GTZ
#define FIFFV_MNE_COORD_RAS
FiffNamedMatrix class declaration.
FiffStream class declaration.
#define FIFFV_BEM_APPROX_LINEAR
#define FIFFV_BEM_APPROX_CONST
#define FIFF_BEM_POT_SOLUTION
MneTriangle class declaration.
MneSourceSpaceOld class declaration.
MneSurfaceOld class declaration.
Forward BEM Solution (FwdBemSolution) class declaration.
FwdCompData class declaration.
FwdEegSphereModel class declaration.
Fwd Thread Argument (FwdThreadArg) class declaration.
FwdBemModel class declaration.
Coordinate transformation descriptor.
QSharedPointer< FiffDirNode > SPtr
void transpose_named_matrix()
QSharedPointer< FiffStream > SPtr
QSharedPointer< FiffTag > SPtr
Holds the BEM model definition.
static QString fwd_bem_make_bem_sol_name(const QString &name)
void fwd_bem_free_solution()
static int compute_forward_meg(MNELIB::MneSourceSpaceOld **spaces, int nspace, FwdCoilSet *coils, FwdCoilSet *comp_coils, MNELIB::MneCTFCompDataSet *comp_data, bool fixed_ori, FwdBemModel *bem_model, Eigen::Vector3f *r0, bool use_threads, FIFFLIB::FiffNamedMatrix &resp, FIFFLIB::FiffNamedMatrix &resp_grad, bool bDoGRad)
static int compute_forward_eeg(MNELIB::MneSourceSpaceOld **spaces, int nspace, FwdCoilSet *els, bool fixed_ori, FwdBemModel *bem_model, FwdEegSphereModel *m, bool use_threads, FIFFLIB::FiffNamedMatrix &resp, FIFFLIB::FiffNamedMatrix &resp_grad, bool bDoGrad)
Mapping from infinite medium potentials to a particular set of coils or electrodes.
FwdCoilSet * dup_coil_set(const FIFFLIB::FiffCoordTransOld *t) const
This structure is used in the compensated field calculations.
Electric Current Dipole description.
static int fwd_eeg_spherepot_coil_vec(float *rd, FwdCoilSet *els, float **Vval_vec, void *client)
static int fwd_eeg_spherepot_coil(float *rd, float *Q, FwdCoilSet *els, float *Vval, void *client)
Filter Thread Argument Description.
One MNE CTF Compensation Data Set description.
This defines a source space.