59 #include <QtConcurrent>
61 #define _USE_MATH_DEFINES
64 #include <Eigen/Dense>
66 static float Qx[] = {1.0,0.0,0.0};
67 static float Qy[] = {0.0,1.0,0.0};
68 static 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))
120 void mne_free_cmatrix_40 (
float **m)
128 static 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");
145 float **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);
163 Eigen::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];
174 void 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);
181 void fromFloatEigenMatrix_40(
const Eigen::MatrixXf& from_mat,
float **& to_mat)
183 fromFloatEigenMatrix_40(from_mat, to_mat, from_mat.rows(), from_mat.cols());
186 float **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);
198 void 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];
215 float 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];
234 void 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];
249 void 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++)
263 #include <Eigen/Core>
264 using namespace Eigen;
266 float **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" },
334 { -1 ,
"unknown" } };
339 } method_expl[] = { { FWD_BEM_CONSTANT_COLL ,
"constant collocation" },
340 { FWD_BEM_LINEAR_COLL ,
"linear collocation" },
341 { -1 ,
"unknown" } };
345 #define BEM_SUFFIX "-bem.fif"
346 #define BEM_SOL_SUFFIX "-bem-sol.fif"
350 static QString strip_from(
const QString& s,
const QString& suffix)
354 if (s.endsWith(suffix)) {
356 res.chop(suffix.size());
376 const 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;
409 using namespace Eigen;
410 using namespace FIFFLIB;
411 using namespace MNELIB;
412 using namespace FWDLIB;
418 FwdBemModel::FwdBemModel()
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);
484 const 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;
497 const 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());
545 FwdBemModel *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++)
627 FwdBemModel *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);
640 FwdBemModel *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);
653 int 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");
781 MneSurfaceOld* 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);
853 double 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;
870 void 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);
977 void 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;
1048 float **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);
1125 int 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);
1188 float **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));
1228 float **FwdBemModel::fwd_bem_homog_solution(
float **solids,
int ntri)
1236 return fwd_bem_multi_solution (solids,NULL,1,&ntri);
1241 void 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);
1317 int 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",
1352 float **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);
1410 int 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);
1471 int 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);
1492 int 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);
1526 float 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)));
1543 float 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();
1653 void 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);
1715 void 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);
1762 void 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);
1825 void 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);
1871 int 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);
1904 int 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)))
1945 void 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++) {
1972 void 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));
1987 void 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;
2102 double 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;
2211 double 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;
2227 void 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;
2296 void 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;
2328 void 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);
2506 void 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];
2568 void 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];
2630 void 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];
2709 float 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;
2730 float 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));
2751 void 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];
2831 int 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);
2862 int 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);
2926 void *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);
3583 int 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;
3686 int 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];
3797 int 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];
3959 int 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)
3995 int 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++)