v2.0.0
Loading...
Searching...
No Matches
dipole_fit_data.cpp
Go to the documentation of this file.
1
2#include <fwd/fwd_types.h>
3
4#include "dipole_fit_data.h"
5#include "guess_data.h"
8#include <mne/mne_proj_item.h>
10#include "ecd.h"
11
12#include <fiff/fiff_stream.h>
14#include <fwd/fwd_bem_model.h>
15#include <mne/mne_surface.h>
16
17#include <fwd/fwd_comp_data.h>
18
19#include <Eigen/Dense>
20
21#include <QFile>
22#include <QTextStream>
23#include <QCoreApplication>
24#include <QDebug>
25
26#define _USE_MATH_DEFINES
27#include <math.h>
28
29using namespace Eigen;
30using namespace FIFFLIB;
31using namespace MNELIB;
32using namespace FWDLIB;
33using namespace INVERSELIB;
34
35//============================= ctf_types.h =============================
36
37#ifndef FIFFV_COIL_CTF_GRAD
38#define FIFFV_COIL_CTF_GRAD 5001
39#endif
40
41#ifndef FIFFV_COIL_CTF_REF_MAG
42#define FIFFV_COIL_CTF_REF_MAG 5002
43#endif
44
45#ifndef FIFFV_COIL_CTF_REF_GRAD
46#define FIFFV_COIL_CTF_REF_GRAD 5003
47#endif
48
49#ifndef FIFFV_COIL_CTF_OFFDIAG_REF_GRAD
50#define FIFFV_COIL_CTF_OFFDIAG_REF_GRAD 5004
51#endif
52
53#ifndef TRUE
54#define TRUE 1
55#endif
56
57#ifndef FALSE
58#define FALSE 0
59#endif
60
61#ifndef FAIL
62#define FAIL -1
63#endif
64
65#ifndef OK
66#define OK 0
67#endif
68
69#define X_3 0
70#define Y_3 1
71#define Z_3 2
72
73#define MALLOC_3(x,t) (t *)malloc((x)*sizeof(t))
74#define REALLOC_3(x,y,t) (t *)((x == NULL) ? malloc((y)*sizeof(t)) : realloc((x),(y)*sizeof(t)))
75#define FREE_3(x) if ((char *)(x) != NULL) free((char *)(x))
76
77/*
78 * Float, double, and int arrays
79 */
80#define ALLOC_FLOAT_3(x) MALLOC_3(x,float)
81
82#define ALLOC_DCMATRIX_3(x,y) mne_dmatrix_3((x),(y))
83#define ALLOC_CMATRIX_3(x,y) mne_cmatrix_3((x),(y))
84#define FREE_CMATRIX_3(m) mne_free_cmatrix_3((m))
85#define FREE_DCMATRIX_3(m) mne_free_dcmatrix_3((m))
86
87static void matrix_error_3(int kind, int nr, int nc)
88
89{
90 if (kind == 1)
91 printf("Failed to allocate memory pointers for a %d x %d matrix\n",nr,nc);
92 else if (kind == 2)
93 printf("Failed to allocate memory for a %d x %d matrix\n",nr,nc);
94 else
95 printf("Allocation error for a %d x %d matrix\n",nr,nc);
96 if (sizeof(void *) == 4) {
97 printf("This is probably because you seem to be using a computer with 32-bit architecture.\n");
98 printf("Please consider moving to a 64-bit platform.");
99 }
100 printf("Cannot continue. Sorry.\n");
101 exit(1);
102}
103
104float **mne_cmatrix_3 (int nr,int nc)
105
106{
107 int i;
108 float **m;
109 float *whole;
110
111 m = MALLOC_3(nr,float *);
112 if (!m) matrix_error_3(1,nr,nc);
113 whole = MALLOC_3(nr*nc,float);
114 if (!whole) matrix_error_3(2,nr,nc);
115
116 for(i=0;i<nr;i++)
117 m[i] = whole + i*nc;
118 return m;
119}
120
121double **mne_dmatrix_3(int nr, int nc)
122
123{
124 int i;
125 double **m;
126 double *whole;
127
128 m = MALLOC_3(nr,double *);
129 if (!m) matrix_error_3(1,nr,nc);
130 whole = MALLOC_3(nr*nc,double);
131 if (!whole) matrix_error_3(2,nr,nc);
132
133 for(i=0;i<nr;i++)
134 m[i] = whole + i*nc;
135 return m;
136}
137
138void mne_free_dcmatrix_3 (double **m)
139
140{
141 if (m) {
142 FREE_3(*m);
143 FREE_3(m);
144 }
145}
146
147/*
148 * Dot product and length
149 */
150#define VEC_DOT_3(x,y) ((x)[X_3]*(y)[X_3] + (x)[Y_3]*(y)[Y_3] + (x)[Z_3]*(y)[Z_3])
151#define VEC_LEN_3(x) sqrt(VEC_DOT_3(x,x))
152
153/*
154 * Others...
155 */
156
157#define VEC_DIFF_3(from,to,diff) {\
158 (diff)[X_3] = (to)[X_3] - (from)[X_3];\
159 (diff)[Y_3] = (to)[Y_3] - (from)[Y_3];\
160 (diff)[Z_3] = (to)[Z_3] - (from)[Z_3];\
161 }
162
163#define VEC_COPY_3(to,from) {\
164 (to)[X_3] = (from)[X_3];\
165 (to)[Y_3] = (from)[Y_3];\
166 (to)[Z_3] = (from)[Z_3];\
167 }
168
169#define CROSS_PRODUCT_3(x,y,xy) {\
170 (xy)[X_3] = (x)[Y_3]*(y)[Z_3]-(y)[Y_3]*(x)[Z_3];\
171 (xy)[Y_3] = -((x)[X_3]*(y)[Z_3]-(y)[X_3]*(x)[Z_3]);\
172 (xy)[Z_3] = (x)[X_3]*(y)[Y_3]-(y)[X_3]*(x)[Y_3];\
173 }
174
175//============================= mne_matop.c =============================
176
177#define MIN_3(a,b) ((a) < (b) ? (a) : (b))
178
179void mne_transpose_square_3(float **mat, int n)
180/*
181 * In-place transpose of a square matrix
182 */
183{
184 int j,k;
185 float val;
186
187 for (j = 1; j < n; j++)
188 for (k = 0; k < j; k++) {
189 val = mat[j][k];
190 mat[j][k] = mat[k][j];
191 mat[k][j] = val;
192 }
193 return;
194}
195
196float mne_dot_vectors_3(float *v1,
197 float *v2,
198 int nn)
199
200{
201#ifdef BLAS
202 int one = 1;
203 float res = sdot(&nn,v1,&one,v2,&one);
204 return res;
205#else
206 float res = 0.0;
207 int k;
208
209 for (k = 0; k < nn; k++)
210 res = res + v1[k]*v2[k];
211 return res;
212#endif
213}
214
215void mne_add_scaled_vector_to_3(float *v1,float scale, float *v2,int nn)
216
217{
218#ifdef BLAS
219 float fscale = scale;
220 int one = 1;
221 saxpy(&nn,&fscale,v1,&one,v2,&one);
222#else
223 int k;
224 for (k = 0; k < nn; k++)
225 v2[k] = v2[k] + scale*v1[k];
226#endif
227 return;
228}
229
230double **mne_dmatt_dmat_mult2_3 (double **m1,double **m2, int d1,int d2,int d3)
231/* Matrix multiplication
232 * result(d1 x d3) = m1(d2 x d1)^T * m2(d2 x d3) */
233
234{
235 double **result = ALLOC_DCMATRIX_3(d1,d3);
236#ifdef BLAS
237 char *transa = "N";
238 char *transb = "T";
239 double zero = 0.0;
240 double one = 1.0;
241
242 dgemm (transa,transb,&d3,&d1,&d2,
243 &one,m2[0],&d3,m1[0],&d1,&zero,result[0],&d3);
244
245 return result;
246#else
247 int j,k,p;
248 double sum;
249
250 for (j = 0; j < d1; j++)
251 for (k = 0; k < d3; k++) {
252 sum = 0.0;
253 for (p = 0; p < d2; p++)
254 sum = sum + m1[p][j]*m2[p][k];
255 result[j][k] = sum;
256 }
257 return result;
258#endif
259}
260
261float **mne_mat_mat_mult_3 (float **m1,float **m2,int d1,int d2,int d3)
262/* Matrix multiplication
263 * result(d1 x d3) = m1(d1 x d2) * m2(d2 x d3) */
264
265{
266#ifdef BLAS
267 float **result = ALLOC_CMATRIX_3(d1,d3);
268 char *transa = "N";
269 char *transb = "N";
270 float zero = 0.0;
271 float one = 1.0;
272 sgemm (transa,transb,&d3,&d1,&d2,
273 &one,m2[0],&d3,m1[0],&d2,&zero,result[0],&d3);
274 return (result);
275#else
276 float **result = ALLOC_CMATRIX_3(d1,d3);
277 int j,k,p;
278 float sum;
279
280 for (j = 0; j < d1; j++)
281 for (k = 0; k < d3; k++) {
282 sum = 0.0;
283 for (p = 0; p < d2; p++)
284 sum = sum + m1[j][p]*m2[p][k];
285 result[j][k] = sum;
286 }
287 return (result);
288#endif
289}
290
291void mne_mat_vec_mult2_3(float **m,float *v,float *result, int d1,int d2)
292/*
293 * Matrix multiplication
294 * result(d1) = m(d1 x d2) * v(d2)
295 */
296
297{
298 int j;
299
300 for (j = 0; j < d1; j++)
301 result[j] = mne_dot_vectors_3(m[j],v,d2);
302 return;
303}
304
305//============================= mne_named_matrix.c =============================
306
307QString mne_name_list_to_string_3(const QStringList& list)
308/*
309 * Convert a string array to a colon-separated string
310 */
311{
312 int nlist = list.size();
313 QString res;
314 if (nlist == 0 || list.isEmpty())
315 return res;
316// res[0] = '\0';
317 for (int k = 0; k < nlist-1; k++) {
318 res += list[k];
319 res += ":";
320 }
321 res += list[nlist-1];
322 return res;
323}
324
325QString mne_channel_names_to_string_3(const QList<FiffChInfo>& chs, int nch)
326/*
327 * Make a colon-separated string out of channel names
328 */
329{
330 QStringList names;
331 QString res;
332 int k;
333
334 if (nch <= 0)
335 return NULL;
336 for (k = 0; k < nch; k++)
337 names.append(chs[k].ch_name);
338 res = mne_name_list_to_string_3(names);
339 names.clear();
340 return res;
341}
342
343void mne_string_to_name_list_3(const QString& s, QStringList& listp,int &nlistp)
344/*
345 * Convert a colon-separated list into a string array
346 */
347{
348 QStringList list;
349
350 if (!s.isEmpty() && s.size() > 0) {
352 //list = s.split(":");
353 }
354 listp = list;
355 nlistp = list.size();
356 return;
357}
358
359//============================= mne_sparse_matop.c =============================
360
361FiffSparseMatrix* mne_convert_to_sparse_3(float **dense, /* The dense matrix to be converted */
362 int nrow, /* Number of rows in the dense matrix */
363 int ncol, /* Number of columns in the dense matrix */
364 int stor_type, /* Either FIFFTS_MC_CCS or FIFFTS_MC_RCS */
365 float small) /* How small elements should be ignored? */
366/*
367 * Create the compressed row or column storage sparse matrix representation
368 * including a vector containing the nonzero matrix element values,
369 * the row or column pointer vector and the appropriate index vector(s).
370 */
371{
372 int j,k;
373 int nz;
374 int ptr;
375 FiffSparseMatrix* sparse = NULL;
376
377 if (small < 0) { /* Automatic scaling */
378 float maxval = 0.0;
379 float val;
380
381 for (j = 0; j < nrow; j++)
382 for (k = 0; k < ncol; k++) {
383 val = std::fabs(dense[j][k]);
384 if (val > maxval)
385 maxval = val;
386 }
387 if (maxval > 0)
388 small = maxval * std::fabs(small);
389 else
390 small = std::fabs(small);
391 }
392 for (j = 0, nz = 0; j < nrow; j++)
393 for (k = 0; k < ncol; k++) {
394 if (std::fabs(dense[j][k]) > small)
395 nz++;
396 }
397
398 if (nz <= 0) {
399 qWarning("No nonzero elements found.");
400 return NULL;
401 }
402 if (stor_type != FIFFTS_MC_CCS && stor_type != FIFFTS_MC_RCS) {
403 qWarning("Unknown sparse matrix storage type: %d",stor_type);
404 return NULL;
405 }
406 sparse = new FiffSparseMatrix;
407 sparse->coding = stor_type;
408 sparse->m = nrow;
409 sparse->n = ncol;
410 sparse->nz = nz;
411 sparse->data.resize(nz);
412 sparse->inds.resize(nz);
413
414 if (stor_type == FIFFTS_MC_RCS) {
415 sparse->ptrs.resize(nrow + 1);
416 for (j = 0, nz = 0; j < nrow; j++) {
417 ptr = -1;
418 for (k = 0; k < ncol; k++)
419 if (std::fabs(dense[j][k]) > small) {
420 sparse->data[nz] = dense[j][k];
421 if (ptr < 0)
422 ptr = nz;
423 sparse->inds[nz++] = k;
424 }
425 sparse->ptrs[j] = ptr;
426 }
427 sparse->ptrs[nrow] = nz;
428 for (j = nrow - 1; j >= 0; j--) /* Take care of the empty rows */
429 if (sparse->ptrs[j] < 0)
430 sparse->ptrs[j] = sparse->ptrs[j+1];
431 }
432 else if (stor_type == FIFFTS_MC_CCS) {
433 sparse->ptrs.resize(ncol + 1);
434 for (k = 0, nz = 0; k < ncol; k++) {
435 ptr = -1;
436 for (j = 0; j < nrow; j++)
437 if (std::fabs(dense[j][k]) > small) {
438 sparse->data[nz] = dense[j][k];
439 if (ptr < 0)
440 ptr = nz;
441 sparse->inds[nz++] = j;
442 }
443 sparse->ptrs[k] = ptr;
444 }
445 sparse->ptrs[ncol] = nz;
446 for (k = ncol-1; k >= 0; k--) /* Take care of the empty columns */
447 if (sparse->ptrs[k] < 0)
448 sparse->ptrs[k] = sparse->ptrs[k+1];
449 }
450 return sparse;
451}
452
453namespace MNELIB
454{
455
456}
457
459
460{
461 return c->cov_diag.size() > 0;
462}
463
464void mne_scale_vector_3 (double scale,float *v,int nn)
465
466{
467#ifdef BLAS
468 float fscale = scale;
469 int one = 1;
470 sscal(&nn,&fscale,v,&one);
471#else
472 int k;
473 for (k = 0; k < nn; k++)
474 v[k] = v[k]*scale;
475#endif
476}
477
478//float
479Eigen::MatrixXf toFloatEigenMatrix_3(float **mat, const int m, const int n)
480{
481 Eigen::MatrixXf eigen_mat(m,n);
482
483 for ( int i = 0; i < m; ++i)
484 for ( int j = 0; j < n; ++j)
485 eigen_mat(i,j) = mat[i][j];
486
487 return eigen_mat;
488}
489
490void fromFloatEigenMatrix_3(const Eigen::MatrixXf& from_mat, float **& to_mat, const int m, const int n)
491{
492 for ( int i = 0; i < m; ++i)
493 for ( int j = 0; j < n; ++j)
494 to_mat[i][j] = from_mat(i,j);
495}
496
497void fromFloatEigenMatrix_3(const Eigen::MatrixXf& from_mat, float **& to_mat)
498{
499 fromFloatEigenMatrix_3(from_mat, to_mat, from_mat.rows(), from_mat.cols());
500}
501
502void fromFloatEigenVector_3(const Eigen::VectorXf& from_vec, float *to_vec, const int n)
503{
504 for ( int i = 0; i < n; ++i)
505 to_vec[i] = from_vec[i];
506}
507
508float **mne_lu_invert_3(float **mat,int dim)
509/*
510 * Invert a matrix using the LU decomposition from
511 * LAPACK
512 */
513{
514 Eigen::MatrixXf eigen_mat = toFloatEigenMatrix_3(mat, dim, dim);
515 Eigen::MatrixXf eigen_mat_inv = eigen_mat.inverse();
516 fromFloatEigenMatrix_3(eigen_mat_inv, mat);
517 return mat;
518}
519
520void mne_free_cmatrix_3 (float **m)
521{
522 if (m) {
523 FREE_3(*m);
524 FREE_3(m);
525 }
526}
527
528int mne_svd_3(float **mat, /* The matrix */
529 int m,int n, /* m rows n columns */
530 float *sing, /* Singular values (must have size
531 * MIN(m,n)+1 */
532 float **uu, /* Left eigenvectors */
533 float **vv) /* Right eigenvectors */
534/*
535 * Compute the SVD of mat.
536 * The singular vector calculations depend on whether
537 * or not u and v are given.
538 *
539 * The allocations should be done as follows
540 *
541 * mat = ALLOC_CMATRIX_3(m,n);
542 * vv = ALLOC_CMATRIX_3(MIN(m,n),n);
543 * uu = ALLOC_CMATRIX_3(MIN(m,n),m);
544 * sing = MALLOC_3(MIN(m,n),float);
545 *
546 * mat is modified by this operation
547 *
548 * This simply allocates the workspace and calls the
549 * LAPACK Fortran routine
550 */
551
552{
553 int udim = MIN_3(m,n);
554
555 Eigen::MatrixXf eigen_mat = toFloatEigenMatrix_3(mat, m, n);
556
557 //ToDo Optimize computation depending of whether uu or vv are defined
558 Eigen::JacobiSVD< Eigen::MatrixXf > svd(eigen_mat ,Eigen::ComputeFullU | Eigen::ComputeFullV);
559
560 fromFloatEigenVector_3(svd.singularValues(), sing, svd.singularValues().size());
561
562 if (uu != NULL)
563 fromFloatEigenMatrix_3(svd.matrixU().transpose(), uu, udim, m);
564
565 if (vv != NULL)
566 fromFloatEigenMatrix_3(svd.matrixV().transpose(), vv, m, n);
567
568 return 0;
569 // return info;
570}
571
573/*
574 * Free a covariance matrix and all its data
575 */
576{
577 if (c == NULL)
578 return;
579 delete c;
580 return;
581}
582
583#define EPS_3 0.05
584
585int mne_get_values_from_data_3 (float time, /* Interesting time point */
586 float integ, /* Time integration */
587 float **data, /* The data values (time by time) */
588 int nsamp, /* How many time points? */
589 int nch, /* How many channels */
590 float tmin, /* Time of first sample */
591 float sfreq, /* Sampling frequency */
592 int use_abs, /* Use absolute values */
593 float *value) /* The picked values */
594/*
595 * Pick a signal value using linear interpolation
596 */
597{
598 int n1,n2,k;
599 float s1,s2;
600 float f1,f2;
601 float sum;
602 float width;
603 int ch;
604
605 for (ch = 0; ch < nch; ch++) {
606 /*
607 * Find out the correct samples
608 */
609 if (std::fabs(sfreq*integ) < EPS_3) { /* This is the single-sample case */
610 s1 = sfreq*(time - tmin);
611 n1 = floor(s1);
612 f1 = 1.0 + n1 - s1;
613 if (n1 < 0 || n1 > nsamp-1) {
614 printf("Sample value out of range %d (0..%d)",n1,nsamp-1);
615 return(-1);
616 }
617 /*
618 * Avoid rounding error
619 */
620 if (n1 == nsamp-1) {
621 if (std::fabs(f1 - 1.0) < 1e-3)
622 f1 = 1.0;
623 }
624 if (f1 < 1.0 && n1 > nsamp-2) {
625 printf("Sample value out of range %d (0..%d) %.4f",n1,nsamp-1,f1);
626 return(-1);
627 }
628 if (f1 < 1.0) {
629 if (use_abs)
630 sum = f1*std::fabs(data[n1][ch]) + (1.0-f1)*std::fabs(data[n1+1][ch]);
631 else
632 sum = f1*data[n1][ch] + (1.0-f1)*data[n1+1][ch];
633 }
634 else {
635 if (use_abs)
636 sum = std::fabs(data[n1][ch]);
637 else
638 sum = data[n1][ch];
639 }
640 }
641 else { /* Multiple samples */
642 s1 = sfreq*(time - 0.5*integ - tmin);
643 s2 = sfreq*(time + 0.5*integ - tmin);
644 n1 = ceil(s1); n2 = floor(s2);
645 if (n2 < n1) { /* We are within one sample interval */
646 n1 = floor(s1);
647 if (n1 < 0 || n1 > nsamp-2)
648 return (-1);
649 f1 = s1 - n1;
650 f2 = s2 - n1;
651 if (use_abs)
652 sum = 0.5*((f1+f2)*std::fabs(data[n1+1][ch]) + (2.0-f1-f2)*std::fabs(data[n1][ch]));
653 else
654 sum = 0.5*((f1+f2)*data[n1+1][ch] + (2.0-f1-f2)*data[n1][ch]);
655 }
656 else {
657 f1 = n1 - s1;
658 f2 = s2 - n2;
659 if (n1 < 0 || n1 > nsamp-1) {
660 printf("Sample value out of range %d (0..%d)",n1,nsamp-1);
661 return(-1);
662 }
663 if (n2 < 0 || n2 > nsamp-1) {
664 printf("Sample value out of range %d (0..%d)",n2,nsamp-1);
665 return(-1);
666 }
667 if (f1 != 0.0 && n1 < 1)
668 return(-1);
669 if (f2 != 0.0 && n2 > nsamp-2)
670 return(-1);
671 sum = 0.0;
672 width = 0.0;
673 if (n2 > n1) { /* Do the whole intervals */
674 if (use_abs) {
675 sum = 0.5 * std::fabs(data[n1][ch]);
676 for (k = n1+1; k < n2; k++)
677 sum = sum + std::fabs(data[k][ch]);
678 sum = sum + 0.5 * std::fabs(data[n2][ch]);
679 }
680 else {
681 sum = 0.5*data[n1][ch];
682 for (k = n1+1; k < n2; k++)
683 sum = sum + data[k][ch];
684 sum = sum + 0.5*data[n2][ch];
685 }
686 width = n2 - n1;
687 }
688 /*
689 * Add tails
690 */
691 if (use_abs) {
692 if (f1 != 0.0)
693 sum = sum + 0.5*f1*(f1*std::fabs(data[n1-1][ch]) + (2.0-f1)*std::fabs(data[n1][ch]));
694 if (f2 != 0.0)
695 sum = sum + 0.5*f2*(f2*std::fabs(data[n2+1][ch]) + (2.0-f2)*std::fabs(data[n2][ch]));
696 }
697 else {
698 if (f1 != 0.0)
699 sum = sum + 0.5*f1*(f1*data[n1-1][ch] + (2.0-f1)*data[n1][ch]);
700 if (f2 != 0.0)
701 sum = sum + 0.5*f2*(f2*data[n2+1][ch] + (2.0-f2)*data[n2][ch]);
702 }
703 width = width + f1 + f2;
704 sum = sum/width;
705 }
706 }
707 value[ch] = sum;
708 }
709 return (0);
710}
711
712//============================= mne_decompose.c =============================
713
714int mne_decompose_eigen_3(double *mat,
715 double *lambda,
716 Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>& vectors,
717 int dim)
718/*
719 * Compute the eigenvalue decomposition of
720 * a symmetric matrix using the LAPACK routines
721 *
722 * 'mat' contains the lower triangle of the matrix
723 */
724{
725 int np = dim*(dim+1)/2;
726 VectorXd w(dim);
727 VectorXd z(dim*dim);
728 VectorXd dmat(np);
729 float *vecp = vectors.data();
730
731 int info,k;
732 int maxi;
733 double scale;
734
735// idamax workaround begin
736 maxi = 0;
737 for(int i = 0; i < np; ++i)
738 if (std::fabs(mat[i]) > std::fabs(mat[maxi]))
739 maxi = i;
740// idamax workaround end
741
742 scale = 1.0/mat[maxi];
743
744 for (k = 0; k < np; k++)
745 dmat[k] = mat[k]*scale;
746
747// dspev workaround begin
748 MatrixXd dmat_tmp = MatrixXd::Zero(dim,dim);
749 int idx = 0;
750 for (int i = 0; i < dim; ++i) {
751 for(int j = 0; j <= i; ++j) {
752 dmat_tmp(i,j) = dmat[idx];
753 dmat_tmp(j,i) = dmat[idx];
754 ++idx;
755 }
756 }
757 SelfAdjointEigenSolver<MatrixXd> es;
758 es.compute(dmat_tmp);
759 for ( int i = 0; i < dim; ++i )
760 w[i] = es.eigenvalues()[i];
761
762 idx = 0;
763 for ( int j = 0; j < dim; ++j ) {
764 for( int i = 0; i < dim; ++i ) {
765 z[idx] = es.eigenvectors()(i,j);// Column Major
766 ++idx;
767 }
768 }
769// dspev workaround end
770
771 info = 0;
772
773 if (info != 0)
774 printf("Eigenvalue decomposition failed (LAPACK info = %d)",info);
775 else {
776 scale = 1.0/scale;
777 for (k = 0; k < dim; k++)
778 lambda[k] = scale*w[k];
779 for (k = 0; k < dim*dim; k++)
780 vecp[k] = z[k];
781 }
782 if (info == 0)
783 return 0;
784 else
785 return -1;
786}
787
788//============================= mne_cov_matrix.c =============================
789
790/*
791 * Routines for handling the covariance matrices
792 */
793
794static int mne_lt_packed_index_3(int j, int k)
795
796{
797 if (j >= k)
798 return k + j*(j+1)/2;
799 else
800 return j + k*(k+1)/2;
801}
802
803/*
804 * Handle the linear projection operators
805 */
806
808/*
809 * Calculate the inverse square roots for whitening
810 */
811{
812 const Eigen::VectorXd& src = c->lambda.size() > 0 ? c->lambda : c->cov_diag;
813 int k;
814
815 if (src.size() == 0) {
816 qCritical("Covariance matrix is not diagonal or not decomposed.");
817 return FAIL;
818 }
819 c->inv_lambda.resize(c->ncov);
820 for (k = 0; k < c->ncov; k++) {
821 if (src[k] <= 0.0)
822 c->inv_lambda[k] = 0.0;
823 else
824 c->inv_lambda[k] = 1.0/sqrt(src[k]);
825 }
826 return OK;
827}
828
829static int condition_cov_3(MNECovMatrix* c, float rank_threshold, int use_rank)
830
831{
832 double *scale = NULL;
833 double *cov = NULL;
834 double *lambda = NULL;
835 Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> local_eigen;
836 double **data1 = NULL;
837 double **data2 = NULL;
838 double magscale,gradscale,eegscale;
839 int nmag,ngrad,neeg,nok;
840 int j,k;
841 int res = FAIL;
842
843 if (c->cov_diag.size() > 0)
844 return OK;
845 if (c->ch_class.size() == 0) {
846 qCritical("Channels not classified. Rank cannot be determined.");
847 return FAIL;
848 }
849 magscale = gradscale = eegscale = 0.0;
850 nmag = ngrad = neeg = 0;
851 for (k = 0; k < c->ncov; k++) {
852 if (c->ch_class[k] == MNE_COV_CH_MEG_MAG) {
853 magscale += c->cov[mne_lt_packed_index_3(k,k)]; nmag++;
854 }
855 else if (c->ch_class[k] == MNE_COV_CH_MEG_GRAD) {
856 gradscale += c->cov[mne_lt_packed_index_3(k,k)]; ngrad++;
857 }
858 else if (c->ch_class[k] == MNE_COV_CH_EEG) {
859 eegscale += c->cov[mne_lt_packed_index_3(k,k)]; neeg++;
860 }
861#ifdef DEBUG
862 fprintf(stdout,"%d ",c->ch_class[k]);
863#endif
864 }
865#ifdef DEBUG
866 fprintf(stdout,"\n");
867#endif
868 if (nmag > 0)
869 magscale = magscale > 0.0 ? sqrt(nmag/magscale) : 0.0;
870 if (ngrad > 0)
871 gradscale = gradscale > 0.0 ? sqrt(ngrad/gradscale) : 0.0;
872 if (neeg > 0)
873 eegscale = eegscale > 0.0 ? sqrt(neeg/eegscale) : 0.0;
874#ifdef DEBUG
875 fprintf(stdout,"%d %g\n",nmag,magscale);
876 fprintf(stdout,"%d %g\n",ngrad,gradscale);
877 fprintf(stdout,"%d %g\n",neeg,eegscale);
878#endif
879 scale = MALLOC_3(c->ncov,double);
880 for (k = 0; k < c->ncov; k++) {
881 if (c->ch_class[k] == MNE_COV_CH_MEG_MAG)
882 scale[k] = magscale;
883 else if (c->ch_class[k] == MNE_COV_CH_MEG_GRAD)
884 scale[k] = gradscale;
885 else if (c->ch_class[k] == MNE_COV_CH_EEG)
886 scale[k] = eegscale;
887 else
888 scale[k] = 1.0;
889 }
890 cov = MALLOC_3(c->ncov*(c->ncov+1)/2.0,double);
891 lambda = MALLOC_3(c->ncov,double);
892 local_eigen.resize(c->ncov,c->ncov);
893 for (j = 0; j < c->ncov; j++)
894 for (k = 0; k <= j; k++)
895 cov[mne_lt_packed_index_3(j,k)] = c->cov[mne_lt_packed_index_3(j,k)]*scale[j]*scale[k];
896 if (mne_decompose_eigen_3(cov,lambda,local_eigen,c->ncov) == 0) {
897#ifdef DEBUG
898 for (k = 0; k < c->ncov; k++)
899 fprintf(stdout,"%g ",lambda[k]/lambda[c->ncov-1]);
900 fprintf(stdout,"\n");
901#endif
902 nok = 0;
903 for (k = c->ncov-1; k >= 0; k--) {
904 if (lambda[k] >= rank_threshold*lambda[c->ncov-1])
905 nok++;
906 else
907 break;
908 }
909 printf("\n\tEstimated covariance matrix rank = %d (%g)\n",nok,lambda[c->ncov-nok]/lambda[c->ncov-1]);
910 if (use_rank > 0 && use_rank < nok) {
911 nok = use_rank;
912 printf("\tUser-selected covariance matrix rank = %d (%g)\n",nok,lambda[c->ncov-nok]/lambda[c->ncov-1]);
913 }
914 /*
915 * Put it back together
916 */
917 for (j = 0; j < c->ncov-nok; j++)
918 lambda[j] = 0.0;
919 data1 = ALLOC_DCMATRIX_3(c->ncov,c->ncov);
920 for (j = 0; j < c->ncov; j++) {
921#ifdef DEBUG
922 mne_print_vector(stdout,NULL,local_eigen.row(j).data(),c->ncov);
923#endif
924 for (k = 0; k < c->ncov; k++)
925 data1[j][k] = sqrt(lambda[j])*local_eigen(j,k);
926 }
927 data2 = mne_dmatt_dmat_mult2_3(data1,data1,c->ncov,c->ncov,c->ncov);
928#ifdef DEBUG
929 printf(">>>\n");
930 for (j = 0; j < c->ncov; j++)
931 mne_print_dvector(stdout,NULL,data2[j],c->ncov);
932 printf(">>>\n");
933#endif
934 /*
935 * Scale back
936 */
937 for (k = 0; k < c->ncov; k++)
938 if (scale[k] > 0.0)
939 scale[k] = 1.0/scale[k];
940 for (j = 0; j < c->ncov; j++)
941 for (k = 0; k <= j; k++)
942 if (c->cov[mne_lt_packed_index_3(j,k)] != 0.0)
943 c->cov[mne_lt_packed_index_3(j,k)] = scale[j]*scale[k]*data2[j][k];
944 res = nok;
945 }
946 FREE_3(cov);
947 FREE_3(scale);
948 FREE_3(lambda);
949 FREE_DCMATRIX_3(data1);
950 FREE_DCMATRIX_3(data2);
951 return res;
952}
953
954static int check_cov_data(double *vals, int nval)
955
956{
957 int k;
958 double sum;
959
960 for (k = 0, sum = 0.0; k < nval; k++)
961 sum += vals[k];
962 if (sum == 0.0) {
963 qCritical("Sum of covariance matrix elements is zero!");
964 return FAIL;
965 }
966 return OK;
967}
968
970 const QList<FiffChInfo>& chs,
971 int nchan)
972/*
973 * Assign channel classes in a covariance matrix with help of channel infos
974 */
975{
976 int k,p;
977 FiffChInfo ch;
978
979 if (chs.isEmpty()) {
980 qCritical("Channel information not available in mne_classify_channels_cov");
981 goto bad;
982 }
983 cov->ch_class.resize(cov->ncov);
984 for (k = 0; k < cov->ncov; k++) {
986 for (p = 0; p < nchan; p++) {
987 if (QString::compare(chs[p].ch_name,cov->names[k]) == 0) {
988 ch = chs[p];
989 if (ch.kind == FIFFV_MEG_CH) {
990 if (ch.unit == FIFF_UNIT_T)
992 else
994 }
995 else if (ch.kind == FIFFV_EEG_CH)
996 cov->ch_class[k] = MNE_COV_CH_EEG;
997 break;
998 }
999 }
1000// if (!ch) {
1001// printf("Could not find channel info for channel %s in mne_classify_channels_cov",cov->names[k].toUtf8().constData());
1002// goto bad;
1003// }
1004 }
1005 return OK;
1006
1007bad : {
1008 cov->ch_class.resize(0);
1009 return FAIL;
1010 }
1011}
1012
1013static int mne_decompose_eigen_cov_small_3(MNECovMatrix* c,float small, int use_rank)
1014/*
1015 * Do the eigenvalue decomposition
1016 */
1017{
1018 int np,k,p,rank;
1019 float rank_threshold = 1e-6;
1020
1021 if (small < 0)
1022 small = 1.0;
1023
1024 if (!c)
1025 return OK;
1026 if (c->cov_diag.size() > 0)
1027 return mne_add_inv_cov_3(c);
1028 if (c->lambda.size() > 0 && c->eigen.size() > 0) {
1029 printf("\n\tEigenvalue decomposition had been precomputed.\n");
1030 c->nzero = 0;
1031 for (k = 0; k < c->ncov; k++, c->nzero++)
1032 if (c->lambda[k] > 0)
1033 break;
1034 }
1035 else {
1036 c->lambda.resize(0);
1037 c->eigen.resize(0,0);
1038
1039 if ((rank = condition_cov_3(c,rank_threshold,use_rank)) < 0)
1040 return FAIL;
1041
1042 np = c->ncov*(c->ncov+1)/2;
1043 c->lambda.resize(c->ncov);
1044 c->eigen.resize(c->ncov,c->ncov);
1045 if (mne_decompose_eigen_3(c->cov.data(),c->lambda.data(),c->eigen,c->ncov) != 0)
1046 goto bad;
1047 c->nzero = c->ncov - rank;
1048 for (k = 0; k < c->nzero; k++)
1049 c->lambda[k] = 0.0;
1050 /*
1051 * Find which eigenvectors correspond to EEG/MEG
1052 */
1053 {
1054 float meglike,eeglike;
1055 int nmeg,neeg;
1056
1057 nmeg = neeg = 0;
1058 for (k = c->nzero; k < c->ncov; k++) {
1059 meglike = eeglike = 0.0;
1060 for (p = 0; p < c->ncov; p++) {
1061 if (c->ch_class[p] == MNE_COV_CH_EEG)
1062 eeglike += std::fabs(c->eigen(k,p));
1063 else if (c->ch_class[p] == MNE_COV_CH_MEG_MAG || c->ch_class[p] == MNE_COV_CH_MEG_GRAD)
1064 meglike += std::fabs(c->eigen(k,p));
1065 }
1066 if (meglike > eeglike)
1067 nmeg++;
1068 else
1069 neeg++;
1070 }
1071 printf("\t%d MEG and %d EEG-like channels remain in the whitened data\n",nmeg,neeg);
1072 }
1073 }
1074 return mne_add_inv_cov_3(c);
1075
1076bad : {
1077 c->lambda.resize(0);
1078 c->eigen.resize(0,0);
1079 return FAIL;
1080 }
1081}
1082
1084
1085{
1086 return mne_decompose_eigen_cov_small_3(c,-1.0,-1);
1087}
1088
1089//============================= mne_whiten.c =============================
1090
1091int mne_whiten_data(float **data, float **whitened_data, int np, int nchan, MNECovMatrix* C)
1092/*
1093 * Apply the whitening operation
1094 */
1095{
1096 int j,k;
1097 float *one = NULL,*orig,*white;
1098 double *inv;
1099
1100 if (data == NULL || np <= 0)
1101 return OK;
1102
1103 if (C->ncov != nchan) {
1104 printf("Incompatible covariance matrix. Cannot whiten the data.");
1105 return FAIL;
1106 }
1107 inv = C->inv_lambda.data();
1108 if (mne_is_diag_cov_3(C)) {
1109 // printf("<DEBUG> Performing Diag\n");
1110 for (j = 0; j < np; j++) {
1111 orig = data[j];
1112 white = whitened_data[j];
1113 for (k = 0; k < nchan; k++)
1114 white[k] = orig[k]*inv[k];
1115 }
1116 }
1117 else {
1118 /*
1119 * This is arranged so that whitened_data can be the same matrix as the original
1120 */
1121 one = MALLOC_3(nchan,float);
1122 for (j = 0; j < np; j++) {
1123 orig = data[j];
1124 white = whitened_data[j];
1125 for (k = C->nzero; k < nchan; k++)
1126 one[k] = mne_dot_vectors_3(C->eigen.row(k).data(),orig,nchan);
1127 for (k = 0; k < C->nzero; k++)
1128 white[k] = 0.0;
1129 for (k = C->nzero; k < nchan; k++)
1130 white[k] = one[k]*inv[k];
1131 }
1132 FREE_3(one);
1133 }
1134 return OK;
1135}
1136
1137int mne_whiten_one_data(float *data, float *whitened_data, int nchan, MNECovMatrix* C)
1138
1139{
1140 float *datap[1];
1141 float *whitened_datap[1];
1142
1143 datap[0] = data;
1144 whitened_datap[0] = whitened_data;
1145
1146 return mne_whiten_data(datap,whitened_datap,1,nchan,C);
1147}
1148
1149//=============================================================================================================
1150//============================= dipole_fit_setup.c =============================
1151static void free_dipole_fit_funcs(dipoleFitFuncs f)
1152
1153{
1154 if (!f)
1155 return;
1156
1157 if (f->meg_client_free && f->meg_client)
1159 if (f->eeg_client_free && f->eeg_client)
1161
1162 FREE_3(f);
1163 return;
1164}
1165
1166//static void regularize_cov(MNECovMatrix* c, /* The matrix to regularize */
1167// float *regs, /* Regularization values to apply (fractions of the
1168// * average diagonal values for each class */
1169// int *active) /* Which of the channels are 'active' */
1171// * Regularize different parts of the noise covariance matrix differently
1172// */
1173//{
1174// int j;
1175// float sums[3],nn[3];
1176// int nkind = 3;
1177
1178// if (!c->cov || !c->ch_class)
1179// return;
1180
1181// for (j = 0; j < nkind; j++) {
1182// sums[j] = 0.0;
1183// nn[j] = 0;
1184// }
1185// /*
1186// * Compute the averages over the diagonal elements for each class
1187// */
1188// for (j = 0; j < c->ncov; j++) {
1189// if (c->ch_class[j] >= 0) {
1190// if (!active || active[j]) {
1191// sums[c->ch_class[j]] += c->cov[mne_lt_packed_index_3(j,j)];
1192// nn[c->ch_class[j]]++;
1193// }
1194// }
1195// }
1196// printf("Average noise-covariance matrix diagonals:\n");
1197// for (j = 0; j < nkind; j++) {
1198// if (nn[j] > 0) {
1199// sums[j] = sums[j]/nn[j];
1200// if (j == MNE_COV_CH_MEG_MAG)
1201// printf("\tMagnetometers : %-7.2f fT reg = %-6.2f\n",1e15*sqrt(sums[j]),regs[j]);
1202// else if (j == MNE_COV_CH_MEG_GRAD)
1203// printf("\tPlanar gradiometers : %-7.2f fT/cm reg = %-6.2f\n",1e13*sqrt(sums[j]),regs[j]);
1204// else
1205// printf("\tEEG : %-7.2f uV reg = %-6.2f\n",1e6*sqrt(sums[j]),regs[j]);
1206// sums[j] = regs[j]*sums[j];
1207// }
1208// }
1209// /*
1210// * Add thee proper amount to the diagonal
1211// */
1212// for (j = 0; j < c->ncov; j++)
1213// if (c->ch_class[j] >= 0)
1214// c->cov[mne_lt_packed_index_3(j,j)] += sums[c->ch_class[j]];
1215
1216// printf("Noise-covariance regularized as requested.\n");
1217// return;
1218//}
1219
1220void mne_regularize_cov(MNECovMatrix* c, /* The matrix to regularize */
1221 float *regs) /* Regularization values to apply (fractions of the
1222 * average diagonal values for each class */
1223/*
1224 * Regularize different parts of the noise covariance matrix differently
1225 */
1226{
1227 int j;
1228 float sums[3],nn[3];
1229 int nkind = 3;
1230
1231 if (c->cov.size() == 0 || c->ch_class.size() == 0)
1232 return;
1233
1234 for (j = 0; j < nkind; j++) {
1235 sums[j] = 0.0;
1236 nn[j] = 0;
1237 }
1238 /*
1239 * Compute the averages over the diagonal elements for each class
1240 */
1241 for (j = 0; j < c->ncov; j++) {
1242 if (c->ch_class[j] >= 0) {
1243 sums[c->ch_class[j]] += c->cov[mne_lt_packed_index_3(j,j)];
1244 nn[c->ch_class[j]]++;
1245 }
1246 }
1247 printf("Average noise-covariance matrix diagonals:\n");
1248 for (j = 0; j < nkind; j++) {
1249 if (nn[j] > 0) {
1250 sums[j] = sums[j]/nn[j];
1251 if (j == MNE_COV_CH_MEG_MAG)
1252 printf("\tMagnetometers : %-7.2f fT reg = %-6.2f\n",1e15*sqrt(sums[j]),regs[j]);
1253 else if (j == MNE_COV_CH_MEG_GRAD)
1254 printf("\tPlanar gradiometers : %-7.2f fT/cm reg = %-6.2f\n",1e13*sqrt(sums[j]),regs[j]);
1255 else
1256 printf("\tEEG : %-7.2f uV reg = %-6.2f\n",1e6*sqrt(sums[j]),regs[j]);
1257 sums[j] = regs[j]*sums[j];
1258 }
1259 }
1260 /*
1261 * Add thee proper amount to the diagonal
1262 */
1263 for (j = 0; j < c->ncov; j++)
1264 if (c->ch_class[j] >= 0)
1265 c->cov[mne_lt_packed_index_3(j,j)] += sums[c->ch_class[j]];
1266
1267 printf("Noise-covariance regularized as requested.\n");
1268 return;
1269}
1270
1271//============================= dipole_fit_setup.c =============================
1272
1273static dipoleFitFuncs new_dipole_fit_funcs()
1274
1275{
1277
1278 f->meg_field = NULL;
1279 f->eeg_pot = NULL;
1280 f->meg_vec_field = NULL;
1281 f->eeg_vec_pot = NULL;
1282 f->meg_client = NULL;
1283 f->meg_client_free = NULL;
1284 f->eeg_client = NULL;
1285 f->eeg_client_free = NULL;
1286
1287 return f;
1288}
1289
1290//============================= mne_simplex_fit.c =============================
1291
1292/*
1293 * This routine comes from Numerical recipes
1294 */
1295
1296#define ALPHA 1.0
1297#define BETA 0.5
1298#define GAMMA 2.0
1299
1300static float tryit (float **p,
1301 float *y,
1302 float *psum,
1303 int ndim,
1304 float (*func)(float *x,int npar,void *user_data), /* The function to be evaluated */
1305 void *user_data, /* Data to be passed to the above function in each evaluation */
1306 int ihi,
1307 int *neval,
1308 float fac)
1309
1310{
1311 int j;
1312 float fac1,fac2,ytry,*ptry;
1313
1314 ptry = ALLOC_FLOAT_3(ndim);
1315 fac1 = (1.0-fac)/ndim;
1316 fac2 = fac1-fac;
1317 for (j = 0; j < ndim; j++)
1318 ptry[j] = psum[j]*fac1-p[ihi][j]*fac2;
1319 ytry = (*func)(ptry,ndim,user_data);
1320 ++(*neval);
1321 if (ytry < y[ihi]) {
1322 y[ihi] = ytry;
1323 for (j = 0; j < ndim; j++) {
1324 psum[j] += ptry[j]-p[ihi][j];
1325 p[ihi][j] = ptry[j];
1326 }
1327 }
1328 FREE_3(ptry);
1329 return ytry;
1330}
1331
1332int mne_simplex_minimize(float **p, /* The initial simplex */
1333 float *y, /* Function values at the vertices */
1334 int ndim, /* Number of variables */
1335 float ftol, /* Relative convergence tolerance */
1336 float (*func)(float *x,int npar,void *user_data), /* The function to be evaluated */
1337 void *user_data, /* Data to be passed to the above function in each evaluation */
1338 int max_eval, /* Maximum number of function evaluations */
1339 int *neval, /* Number of function evaluations */
1340 int report, /* How often to report (-1 = no_reporting) */
1341 int (*report_func)(int loop,
1342 float *fitpar, int npar,
1343 double fval)) /* The function to be called when reporting */
1344
1345/*
1346 * Minimization with the simplex algorithm
1347 * Modified from Numerical recipes
1348 */
1349
1350{
1351 int i,j,ilo,ihi,inhi;
1352 int mpts = ndim+1;
1353 float ytry,ysave,sum,rtol,*psum;
1354 int result = 0;
1355 int count = 0;
1356 int loop = 1;
1357
1358 psum = ALLOC_FLOAT_3(ndim);
1359 *neval = 0;
1360 for (j = 0; j < ndim; j++) {
1361 for (i = 0,sum = 0.0; i<mpts; i++)
1362 sum += p[i][j];
1363 psum[j] = sum;
1364 }
1365 if (report_func != NULL && report > 0)
1366 (void)report_func (0,p[0],ndim,-1.0);
1367
1368 for (;;count++,loop++) {
1369 ilo = 1;
1370 ihi = y[1]>y[2] ? (inhi = 2,1) : (inhi = 1,2);
1371 for (i = 0; i < mpts; i++) {
1372 if (y[i] < y[ilo]) ilo = i;
1373 if (y[i] > y[ihi]) {
1374 inhi = ihi;
1375 ihi = i;
1376 } else if (y[i] > y[inhi])
1377 if (i != ihi) inhi = i;
1378 }
1379 rtol = 2.0*std::fabs(y[ihi]-y[ilo])/(std::fabs(y[ihi])+std::fabs(y[ilo]));
1380 /*
1381 * Report that we are proceeding...
1382 */
1383 if (count == report && report_func != NULL) {
1384 if (report_func (loop,p[ilo],ndim,y[ilo])) {
1385 qWarning("Interation interrupted.");
1386 result = -1;
1387 break;
1388 }
1389 count = 0;
1390 }
1391 if (rtol < ftol) break;
1392 if (*neval >= max_eval) {
1393 qWarning("Maximum number of evaluations exceeded.");
1394 result = -1;
1395 break;
1396 }
1397 ytry = tryit(p,y,psum,ndim,func,user_data,ihi,neval,-ALPHA);
1398 if (ytry <= y[ilo])
1399 ytry = tryit(p,y,psum,ndim,func,user_data,ihi,neval,GAMMA);
1400 else if (ytry >= y[inhi]) {
1401 ysave = y[ihi];
1402 ytry = tryit(p,y,psum,ndim,func,user_data,ihi,neval,BETA);
1403 if (ytry >= ysave) {
1404 for (i = 0; i < mpts; i++) {
1405 if (i != ilo) {
1406 for (j = 0; j < ndim; j++) {
1407 psum[j] = 0.5*(p[i][j]+p[ilo][j]);
1408 p[i][j] = psum[j];
1409 }
1410 y[i] = (*func)(psum,ndim,user_data);
1411 }
1412 }
1413 *neval += ndim;
1414 for (j = 0; j < ndim; j++) {
1415 for (i = 0,sum = 0.0; i < mpts; i++)
1416 sum += p[i][j];
1417 psum[j] = sum;
1418 }
1419 }
1420 }
1421 }
1422 FREE_3(psum);
1423 return (result);
1424}
1425
1426#undef ALPHA
1427#undef BETA
1428#undef GAMMA
1429
1430//============================= fit_sphere.c =============================
1431
1432namespace MNELIB
1433{
1434
1443
1444}
1445
1446static int report_func(int loop,
1447 float *fitpar,
1448 int npar,
1449 double fval)
1450/*
1451 * Report periodically
1452 */
1453{
1454 float *r0 = fitpar;
1455 (void) npar; // avoid unused variable warning.
1456
1457 printf("loop %d r0 %7.1f %7.1f %7.1f fval %g\n",
1458 loop,1000*r0[0],1000*r0[1],1000*r0[2],fval);
1459
1460 return OK;
1461}
1462
1463static float fit_sphere_eval(float *fitpar,
1464 int npar,
1465 void *user_data)
1466/*
1467 * Calculate the cost function value
1468 * Optimize for the radius inside here
1469 */
1470{
1471 fitSphereUser user = (fitSphereUser)user_data;
1472 float *r0 = fitpar;
1473 float diff[3];
1474 int k;
1475 float sum,sum2,one,F;
1476 (void) npar; // avoid unused variable warning.
1477
1478 for (k = 0, sum = sum2 = 0.0; k < user->np; k++) {
1479 VEC_DIFF_3(r0,&(*user->rr)(k,0),diff);
1480 one = VEC_LEN_3(diff);
1481 sum += one;
1482 sum2 += one*one;
1483 }
1484 F = sum2 - sum*sum/user->np;
1485
1486 if (user->report)
1487 printf("r0 %7.1f %7.1f %7.1f R %7.1f fval %g\n",
1488 1000*r0[0],1000*r0[1],1000*r0[2],1000*sum/user->np,F);
1489
1490 return F;
1491}
1492
1493static float opt_rad(float *r0,fitSphereUser user)
1494
1495{
1496 float sum, diff[3], one;
1497 int k;
1498
1499 for (k = 0, sum = 0.0; k < user->np; k++) {
1500 VEC_DIFF_3(r0,&(*user->rr)(k,0),diff);
1501 one = VEC_LEN_3(diff);
1502 sum += one;
1503 }
1504 return sum/user->np;
1505}
1506
1507static void calculate_cm_ave_dist(const MNESurfaceOrVolume::PointsT& rr, int np, float *cm, float *avep)
1508
1509{
1510 int k,q;
1511 float ave,diff[3];
1512
1513 for (q = 0; q < 3; q++)
1514 cm[q] = 0.0;
1515
1516 for (k = 0; k < np; k++)
1517 for (q = 0; q < 3; q++)
1518 cm[q] += rr(k,q);
1519
1520 if (np > 0) {
1521 for (q = 0; q < 3; q++)
1522 cm[q] = cm[q]/np;
1523
1524 for (k = 0, ave = 0.0; k < np; k++) {
1525 for (q = 0; q < 3; q++)
1526 diff[q] = rr(k,q) - cm[q];
1527 ave += VEC_LEN_3(diff);
1528 }
1529 *avep = ave/np;
1530 }
1531 return;
1532}
1533
1534static float **make_initial_simplex(float *pars,
1535 int npar,
1536 float size)
1537/*
1538 * Make the initial tetrahedron
1539 */
1540{
1541 float **simplex = ALLOC_CMATRIX_3(npar+1,npar);
1542 int k;
1543
1544 for (k = 0; k < npar+1; k++)
1545 memcpy (simplex[k],pars,npar*sizeof(float));
1546
1547 for (k = 1; k < npar+1; k++)
1548 simplex[k][k-1] = simplex[k][k-1] + size;
1549 return (simplex);
1550}
1551
1553 int np,
1554 float simplex_size,
1555 float *r0,
1556 float *R)
1557/*
1558 * Find the optimal sphere origin
1559 */
1560{
1561 fitSphereUserRec user;
1562 float ftol = 1e-5;
1563 int max_eval = 500;
1564 int report_interval = -1;
1565 int neval = 0;
1566 float **init_simplex = NULL;
1567 float *init_vals = NULL;
1568
1569 float cm[3],R0;
1570 int k;
1571
1572 int res = FAIL;
1573
1574 user.rr = &rr;
1575 user.np = np;
1576
1577 calculate_cm_ave_dist(rr,np,cm,&R0);
1578
1579#ifdef DEBUG
1580 printf("cm %7.1f %7.1f %7.1f R %7.1f\n",
1581 1000*cm[0],1000*cm[1],1000*cm[2],1000*R0);
1582#endif
1583
1584 init_simplex = make_initial_simplex(cm,3,simplex_size);
1585
1586 init_vals = MALLOC_3(4,float);
1587
1588#ifdef DEBUG
1589 user.report = TRUE;
1590#else
1591 user.report = FALSE;
1592#endif
1593
1594 for (k = 0; k < 4; k++)
1595 init_vals[k] = fit_sphere_eval(init_simplex[k],3,&user);
1596
1597 if (mne_simplex_minimize(init_simplex, /* The initial simplex */
1598 init_vals, /* Function values at the vertices */
1599 3, /* Number of variables */
1600 ftol, /* Relative convergence tolerance */
1601 fit_sphere_eval, /* The function to be evaluated */
1602 &user, /* Data to be passed to the above function in each evaluation */
1603 max_eval, /* Maximum number of function evaluations */
1604 &neval, /* Number of function evaluations */
1605 report_interval, /* How often to report (-1 = no_reporting) */
1606 report_func) != OK) /* The function to be called when reporting */
1607 goto out;
1608
1609 r0[X_3] = init_simplex[0][X_3];
1610 r0[Y_3] = init_simplex[0][Y_3];
1611 r0[Z_3] = init_simplex[0][Z_3];
1612 *R = opt_rad(r0,&user);
1613
1614 res = OK;
1615 goto out;
1616
1617out : {
1618 FREE_3(init_vals);
1619 FREE_CMATRIX_3(init_simplex);
1620 return res;
1621 }
1622}
1623
1624//============================= mne_lin_proj.c =============================
1625
1626void mne_proj_op_report_data_3(QTextStream &out,const char *tag, MNEProjOp* op, int list_data,
1627 char **exclude, int nexclude)
1628/*
1629 * Output info about the projection operator
1630 */
1631{
1632 int j,k,p,q;
1633 MNEProjItem* it;
1634 MNENamedMatrix* vecs;
1635 int found;
1636
1637 if (op == NULL)
1638 return;
1639 if (op->nitems <= 0) {
1640 out << "Empty operator\n";
1641 return;
1642 }
1643
1644 for (k = 0; k < op->nitems; k++) {
1645 it = &op->items[k];
1646 if (list_data && tag)
1647 out << tag << "\n";
1648 if (tag)
1649 out << tag;
1650 out << "# " << (k+1) << " : " << it->desc << " : " << it->nvec << " vecs : " << it->vecs->ncol << " chs "
1651 << (it->has_meg ? "MEG" : "EEG") << " "
1652 << (it->active ? "active" : "idle") << "\n";
1653 if (list_data && tag)
1654 out << tag << "\n";
1655 if (list_data) {
1656 vecs = op->items[k].vecs.get();
1657
1658 for (q = 0; q < vecs->ncol; q++) {
1659 out << qSetFieldWidth(10) << Qt::left << vecs->collist[q] << qSetFieldWidth(0);
1660 out << (q < vecs->ncol-1 ? " " : "\n");
1661 }
1662 for (p = 0; p < vecs->nrow; p++)
1663 for (q = 0; q < vecs->ncol; q++) {
1664 for (j = 0, found = 0; j < nexclude; j++) {
1665 if (QString::compare(exclude[j],vecs->collist[q]) == 0) {
1666 found = 1;
1667 break;
1668 }
1669 }
1670 out << qSetFieldWidth(10) << qSetRealNumberPrecision(5) << Qt::forcepoint
1671 << (found ? 0.0 : vecs->data(p, q)) << qSetFieldWidth(0) << " ";
1672 out << (q < vecs->ncol-1 ? " " : "\n");
1673 }
1674 if (list_data && tag)
1675 out << tag << "\n";
1676 }
1677 }
1678 return;
1679}
1680
1681void mne_proj_op_report_3(QTextStream &out,const char *tag, MNEProjOp* op)
1682{
1683 mne_proj_op_report_data_3(out,tag,op, FALSE, NULL, 0);
1684}
1685
1686//============================= mne_named_vector.c =============================
1687
1688int mne_pick_from_named_vector_3(MNENamedVector* vec, const QStringList& names, int nnames, int require_all, float *res)
1689/*
1690 * Pick the desired elements from the named vector
1691 */
1692{
1693 int found;
1694 int k,p;
1695
1696 if (vec->names.size() == 0) {
1697 qCritical("No names present in vector. Cannot pick.");
1698 return FAIL;
1699 }
1700
1701 for (k = 0; k < nnames; k++)
1702 res[k] = 0.0;
1703
1704 for (k = 0; k < nnames; k++) {
1705 found = 0;
1706 for (p = 0; p < vec->nvec; p++) {
1707 if (QString::compare(vec->names[p],names[k]) == 0) {
1708 res[k] = vec->data[p];
1709 found = TRUE;
1710 break;
1711 }
1712 }
1713 if (!found && require_all) {
1714 qCritical("All required elements not found in named vector.");
1715 return FAIL;
1716 }
1717 }
1718 return OK;
1719}
1720
1721//============================= mne_lin_proj_io.c =============================
1722
1724 FiffStream::SPtr& stream,
1725 const FiffDirNode::SPtr& start)
1726/*
1727 * Load all the linear projection data
1728 */
1729{
1730 MNEProjOp* op = NULL;
1731 QList<FiffDirNode::SPtr> proj;
1732 FiffDirNode::SPtr start_node;
1733 QList<FiffDirNode::SPtr> items;
1734 FiffDirNode::SPtr node;
1735 int k;
1736 QString item_desc, desc_tag;
1737 int global_nchan,item_nchan,nlist;
1738 QStringList item_names;
1739 int item_kind;
1740 int item_nvec;
1741 int item_active;
1742 FiffTag::SPtr t_pTag;
1743 QStringList emptyList;
1744 int pos;
1745
1746 if (!stream) {
1747 qCritical("File not open mne_read_proj_op_from_node");
1748 goto bad;
1749 }
1750
1751 if (!start || start->isEmpty())
1752 start_node = stream->dirtree();
1753 else
1754 start_node = start;
1755
1756 op = new MNEProjOp();
1757 proj = start_node->dir_tree_find(FIFFB_PROJ);
1758 if (proj.size() == 0 || proj[0]->isEmpty()) /* The caller must recognize an empty projection */
1759 goto out;
1760 /*
1761 * Only the first projection block is recognized
1762 */
1763 items = proj[0]->dir_tree_find(FIFFB_PROJ_ITEM);
1764 if (items.size() == 0 || items[0]->isEmpty()) /* The caller must recognize an empty projection */
1765 goto out;
1766 /*
1767 * Get a common number of channels
1768 */
1769 node = proj[0];
1770 if(!node->find_tag(stream, FIFF_NCHAN, t_pTag))
1771 global_nchan = 0;
1772 else {
1773 global_nchan = *t_pTag->toInt();
1774// TAG_FREE_3(tag);
1775 }
1776 /*
1777 * Proceess each item
1778 */
1779 for (k = 0; k < items.size(); k++) {
1780 node = items[k];
1781 /*
1782 * Complicated procedure for getting the description
1783 */
1784 item_desc.clear();
1785
1786 if (node->find_tag(stream, FIFF_NAME, t_pTag)) {
1787 item_desc += t_pTag->toString();
1788 }
1789
1790 /*
1791 * Take the first line of description if it exists
1792 */
1793 if (node->find_tag(stream, FIFF_DESCRIPTION, t_pTag)) {
1794 desc_tag = t_pTag->toString();
1795 if((pos = desc_tag.indexOf("\n")) >= 0)
1796 desc_tag.truncate(pos);
1797 if (!item_desc.isEmpty())
1798 item_desc += " ";
1799 item_desc += desc_tag;
1800 }
1801 /*
1802 * Possibility to override number of channels here
1803 */
1804 if (!node->find_tag(stream, FIFF_NCHAN, t_pTag)) {
1805 item_nchan = global_nchan;
1806 }
1807 else {
1808 item_nchan = *t_pTag->toInt();
1809 }
1810 if (item_nchan <= 0) {
1811 qCritical("Number of channels incorrectly specified for one of the projection items.");
1812 goto bad;
1813 }
1814 /*
1815 * Take care of the channel names
1816 */
1817 if (!node->find_tag(stream, FIFF_PROJ_ITEM_CH_NAME_LIST, t_pTag))
1818 goto bad;
1819
1820 mne_string_to_name_list_3(t_pTag->toString(),item_names,nlist);
1821 if (nlist != item_nchan) {
1822 printf("Channel name list incorrectly specified for proj item # %d",k+1);
1823 item_names.clear();
1824 goto bad;
1825 }
1826 /*
1827 * Kind of item
1828 */
1829 if (!node->find_tag(stream, FIFF_PROJ_ITEM_KIND, t_pTag))
1830 goto bad;
1831 item_kind = *t_pTag->toInt();
1832 /*
1833 * How many vectors
1834 */
1835 if (!node->find_tag(stream,FIFF_PROJ_ITEM_NVEC, t_pTag))
1836 goto bad;
1837 item_nvec = *t_pTag->toInt();
1838 /*
1839 * The projection data
1840 */
1841 if (!node->find_tag(stream,FIFF_PROJ_ITEM_VECTORS, t_pTag))
1842 goto bad;
1843
1844 MatrixXf item_vectors = t_pTag->toFloatMatrix().transpose();
1845
1846 /*
1847 * Is this item active?
1848 */
1849 if (node->find_tag(stream, FIFF_MNE_PROJ_ITEM_ACTIVE, t_pTag)) {
1850 item_active = *t_pTag->toInt();
1851 }
1852 else
1853 item_active = FALSE;
1854 /*
1855 * Ready to add
1856 */
1857 auto item = MNENamedMatrix::build(item_nvec,item_nchan,emptyList,item_names,item_vectors);
1858 op->add_item_active(item.get(),item_kind,item_desc,item_active);
1859 op->items[op->nitems-1].active_file = item_active;
1860 }
1861
1862out :
1863 return op;
1864
1865bad : {
1866 if(op)
1867 delete op;
1868 return NULL;
1869 }
1870}
1871
1873
1874{
1875 QFile file(name);
1876 FiffStream::SPtr stream(new FiffStream(&file));
1877
1878 if(!stream->open())
1879 return NULL;
1880
1881 MNEProjOp* res = NULL;
1882
1883 FiffDirNode::SPtr t_default;
1884 res = mne_read_proj_op_from_node_3(stream,t_default);
1885
1886 stream->close();
1887
1888 return res;
1889}
1890
1891int mne_proj_op_chs_3(MNEProjOp* op, const QStringList& list, int nlist)
1892
1893{
1894 if (op == NULL)
1895 return OK;
1896
1897 op->free_proj(); /* These data are not valid any more */
1898
1899 if (nlist == 0)
1900 return OK;
1901
1902 op->names = list;
1903 op->nch = nlist;
1904
1905 return OK;
1906}
1907
1908static void clear_these(float *data, const QStringList& names, int nnames, const QString& start)
1909
1910{
1911 int k;
1912 for (k = 0; k < nnames; k++)
1913 if (names[k].contains(start))//strstr(names[k],start) == names[k])
1914 data[k] = 0.0;
1915}
1916
1917#define USE_LIMIT 1e-5
1918#define SMALL_VALUE 1e-4
1919
1920int mne_proj_op_make_proj_bad(MNEProjOp* op, char **bad, int nbad)
1921/*
1922 * Do the channel picking and SVD
1923 * Include a bad list at this phase
1924 * Input to the projection can include the bad channels
1925 * but they are not affected
1926 */
1927{
1928 int k,p,q,r,nvec;
1929 float **vv_meg = NULL;
1930 float *sing_meg = NULL;
1931 float **vv_eeg = NULL;
1932 float *sing_eeg = NULL;
1933 float **mat_meg = NULL;
1934 float **mat_eeg = NULL;
1935 int nvec_meg;
1936 int nvec_eeg;
1937 MNENamedVector vec;
1938 float size;
1939 int nzero;
1940#ifdef DEBUG
1941 char name[20];
1942#endif
1943
1944 op->proj_data.resize(0, 0);
1945 op->nvec = 0;
1946
1947 if (op->nch <= 0)
1948 return OK;
1949 if (op->nitems <= 0)
1950 return OK;
1951
1952 nvec = op->affect(op->names,op->nch);
1953 if (nvec == 0)
1954 return OK;
1955
1956 mat_meg = ALLOC_CMATRIX_3(nvec, op->nch);
1957 mat_eeg = ALLOC_CMATRIX_3(nvec, op->nch);
1958
1959#ifdef DEBUG
1960 fprintf(stdout,"mne_proj_op_make_proj_bad\n");
1961#endif
1962 for (k = 0, nvec_meg = nvec_eeg = 0; k < op->nitems; k++) {
1963 if (op->items[k].active && op->items[k].affect(op->names,op->nch)) {
1964 vec.nvec = op->items[k].vecs->ncol;
1965 vec.names = op->items[k].vecs->collist;
1966 if (op->items[k].has_meg) {
1967 for (p = 0; p < op->items[k].nvec; p++, nvec_meg++) {
1968 vec.data = op->items[k].vecs->data.row(p);
1969 if (mne_pick_from_named_vector_3(&vec,op->names,op->nch,FALSE,mat_meg[nvec_meg]) == FAIL)
1970 goto bad;
1971#ifdef DEBUG
1972 fprintf(stdout,"Original MEG:\n");
1973 mne_print_vector(stdout,op->items[k].desc,mat_meg[nvec_meg],op->nch);
1974 fflush(stdout);
1975#endif
1976 }
1977 }
1978 else if (op->items[k].has_eeg) {
1979 for (p = 0; p < op->items[k].nvec; p++, nvec_eeg++) {
1980 vec.data = op->items[k].vecs->data.row(p);
1981 if (mne_pick_from_named_vector_3(&vec,op->names,op->nch,FALSE,mat_eeg[nvec_eeg]) == FAIL)
1982 goto bad;
1983#ifdef DEBUG
1984 fprintf (stdout,"Original EEG:\n");
1985 mne_print_vector(stdout,op->items[k].desc,mat_eeg[nvec_eeg],op->nch);
1986 fflush(stdout);
1987#endif
1988 }
1989 }
1990 }
1991 }
1992 /*
1993 * Replace bad channel entries with zeroes
1994 */
1995 for (q = 0; q < nbad; q++)
1996 for (r = 0; r < op->nch; r++)
1997 if (QString::compare(op->names[r],bad[q]) == 0) {
1998 for (p = 0; p < nvec_meg; p++)
1999 mat_meg[p][r] = 0.0;
2000 for (p = 0; p < nvec_eeg; p++)
2001 mat_eeg[p][r] = 0.0;
2002 }
2003 /*
2004 * Scale the rows so that detection of linear dependence becomes easy
2005 */
2006 for (p = 0, nzero = 0; p < nvec_meg; p++) {
2007 size = sqrt(mne_dot_vectors_3(mat_meg[p],mat_meg[p],op->nch));
2008 if (size > 0) {
2009 for (k = 0; k < op->nch; k++)
2010 mat_meg[p][k] = mat_meg[p][k]/size;
2011 }
2012 else
2013 nzero++;
2014 }
2015 if (nzero == nvec_meg) {
2016 FREE_CMATRIX_3(mat_meg); mat_meg = NULL; nvec_meg = 0;
2017 }
2018 for (p = 0, nzero = 0; p < nvec_eeg; p++) {
2019 size = sqrt(mne_dot_vectors_3(mat_eeg[p],mat_eeg[p],op->nch));
2020 if (size > 0) {
2021 for (k = 0; k < op->nch; k++)
2022 mat_eeg[p][k] = mat_eeg[p][k]/size;
2023 }
2024 else
2025 nzero++;
2026 }
2027 if (nzero == nvec_eeg) {
2028 FREE_CMATRIX_3(mat_eeg); mat_eeg = NULL; nvec_eeg = 0;
2029 }
2030 if (nvec_meg + nvec_eeg == 0) {
2031 printf("No projection remains after excluding bad channels. Omitting projection.\n");
2032 return OK;
2033 }
2034 /*
2035 * Proceed to SVD
2036 */
2037#ifdef DEBUG
2038 fprintf(stdout,"Before SVD:\n");
2039#endif
2040 if (nvec_meg > 0) {
2041#ifdef DEBUG
2042 fprintf(stdout,"---->>\n");
2043 for (p = 0; p < nvec_meg; p++) {
2044 sprintf(name,"MEG %02d",p+1);
2045 mne_print_vector(stdout,name,mat_meg[p],op->nch);
2046 }
2047 fprintf(stdout,"---->>\n");
2048#endif
2049 sing_meg = MALLOC_3(nvec_meg+1,float);
2050 vv_meg = ALLOC_CMATRIX_3(nvec_meg,op->nch);
2051 if (mne_svd_3(mat_meg,nvec_meg,op->nch,sing_meg,NULL,vv_meg) != OK)
2052 goto bad;
2053 }
2054 if (nvec_eeg > 0) {
2055#ifdef DEBUG
2056 fprintf(stdout,"---->>\n");
2057 for (p = 0; p < nvec_eeg; p++) {
2058 sprintf(name,"EEG %02d",p+1);
2059 mne_print_vector(stdout,name,mat_eeg[p],op->nch);
2060 }
2061 fprintf(stdout,"---->>\n");
2062#endif
2063 sing_eeg = MALLOC_3(nvec_eeg+1,float);
2064 vv_eeg = ALLOC_CMATRIX_3(nvec_eeg,op->nch);
2065 if (mne_svd_3(mat_eeg,nvec_eeg,op->nch,sing_eeg,NULL,vv_eeg) != OK)
2066 goto bad;
2067 }
2068 /*
2069 * Check for linearly dependent vectors
2070 */
2071 for (p = 0, op->nvec = 0; p < nvec_meg; p++, op->nvec++)
2072 if (sing_meg[p]/sing_meg[0] < USE_LIMIT)
2073 break;
2074 for (p = 0; p < nvec_eeg; p++, op->nvec++)
2075 if (sing_eeg[p]/sing_eeg[0] < USE_LIMIT)
2076 break;
2077#ifdef DEBUG
2078 printf("Number of linearly independent vectors = %d\n",op->nvec);
2079#endif
2080 op->proj_data = MNEProjOp::RowMajorMatrixXf::Zero(op->nvec,op->nch);
2081#ifdef DEBUG
2082 fprintf(stdout,"Final projection data:\n");
2083#endif
2084 for (p = 0, op->nvec = 0; p < nvec_meg; p++, op->nvec++) {
2085 if (sing_meg[p]/sing_meg[0] < USE_LIMIT)
2086 break;
2087 for (k = 0; k < op->nch; k++) {
2088 /*
2089 * Avoid crosstalk between MEG/EEG
2090 */
2091 if (std::fabs(vv_meg[p][k]) < SMALL_VALUE)
2092 op->proj_data(op->nvec,k) = 0.0;
2093 else
2094 op->proj_data(op->nvec,k) = vv_meg[p][k];
2095
2096 /*
2097 * If the above did not work, this will (provided that EEG channels are called EEG*)
2098 */
2099 clear_these(op->proj_data.row(op->nvec).data(),op->names,op->nch,"EEG");
2100 }
2101#ifdef DEBUG
2102 sprintf(name,"MEG %02d",p+1);
2103 mne_print_vector(stdout,name,op->proj_data.row(op->nvec).data(),op->nch);
2104#endif
2105 }
2106 for (p = 0; p < nvec_eeg; p++, op->nvec++) {
2107 if (sing_eeg[p]/sing_eeg[0] < USE_LIMIT)
2108 break;
2109 for (k = 0; k < op->nch; k++) {
2110 /*
2111 * Avoid crosstalk between MEG/EEG
2112 */
2113 if (std::fabs(vv_eeg[p][k]) < SMALL_VALUE)
2114 op->proj_data(op->nvec,k) = 0.0;
2115 else
2116 op->proj_data(op->nvec,k) = vv_eeg[p][k];
2117 /*
2118 * If the above did not work, this will (provided that MEG channels are called MEG*)
2119 */
2120 clear_these(op->proj_data.row(op->nvec).data(),op->names,op->nch,"MEG");
2121 }
2122#ifdef DEBUG
2123 sprintf(name,"EEG %02d",p+1);
2124 mne_print_vector(stdout,name,op->proj_data.row(op->nvec).data(),op->nch);
2125 fflush(stdout);
2126#endif
2127 }
2128 FREE_3(sing_meg);
2129 FREE_CMATRIX_3(vv_meg);
2130 FREE_CMATRIX_3(mat_meg);
2131 FREE_3(sing_eeg);
2132 FREE_CMATRIX_3(vv_eeg);
2133 FREE_CMATRIX_3(mat_eeg);
2134 /*
2135 * Make sure that the stimulus channels are not modified
2136 */
2137 for (k = 0; k < op->nch; k++)
2138 if (op->names[k].contains("STI")){ //strstr(op->names[k],"STI") == op->names[k]) {
2139 for (p = 0; p < op->nvec; p++)
2140 op->proj_data(p,k) = 0.0;
2141 }
2142
2143 return OK;
2144
2145bad : {
2146 FREE_3(sing_meg);
2147 FREE_CMATRIX_3(vv_meg);
2148 FREE_CMATRIX_3(mat_meg);
2149 FREE_3(sing_eeg);
2150 FREE_CMATRIX_3(vv_eeg);
2151 FREE_CMATRIX_3(mat_eeg);
2152 return FAIL;
2153 }
2154}
2155
2157/*
2158 * Do the channel picking and SVD
2159 */
2160{
2161 return mne_proj_op_make_proj_bad(op,NULL,0);
2162}
2163
2164//============================= mne_read_forward_solution.c =============================
2165
2167 QList<FiffChInfo>& megp, /* MEG channels */
2168 int *nmegp,
2169 QList<FiffChInfo>& meg_compp,
2170 int *nmeg_compp,
2171 QList<FiffChInfo>& eegp, /* EEG channels */
2172 int *neegp,
2173 FiffCoordTrans *meg_head_t,
2174 fiffId *idp) /* The measurement ID */
2175/*
2176 * Read the channel information and split it into three arrays,
2177 * one for MEG, one for MEG compensation channels, and one for EEG
2178 */
2179{
2180 QFile file(name);
2181 FiffStream::SPtr stream(new FiffStream(&file));
2182
2183 QList<FiffChInfo> chs;
2184 int nchan = 0;
2185 QList<FiffChInfo> meg;
2186 int nmeg = 0;
2187 QList<FiffChInfo> meg_comp;
2188 int nmeg_comp = 0;
2189 QList<FiffChInfo> eeg;
2190 int neeg = 0;
2191 fiffId id = NULL;
2192 QList<FiffDirNode::SPtr> nodes;
2193 FiffDirNode::SPtr info;
2194 FiffTag::SPtr t_pTag;
2195 FiffChInfo this_ch;
2197 fiff_int_t kind, pos;
2198 int j,k,to_find;
2199
2200 if(!stream->open())
2201 goto bad;
2202
2203 nodes = stream->dirtree()->dir_tree_find(FIFFB_MNE_PARENT_MEAS_FILE);
2204
2205 if (nodes.size() == 0) {
2206 nodes = stream->dirtree()->dir_tree_find(FIFFB_MEAS_INFO);
2207 if (nodes.size() == 0) {
2208 qCritical ("Could not find the channel information.");
2209 goto bad;
2210 }
2211 }
2212 info = nodes[0];
2213 to_find = 0;
2214 for (k = 0; k < info->nent(); k++) {
2215 kind = info->dir[k]->kind;
2216 pos = info->dir[k]->pos;
2217 switch (kind) {
2218 case FIFF_NCHAN :
2219 if (!stream->read_tag(t_pTag,pos))
2220 goto bad;
2221 nchan = *t_pTag->toInt();
2222
2223 for (j = 0; j < nchan; j++)
2224 chs.append(FiffChInfo());
2225 chs[j].scanNo = -1;
2226 to_find = nchan;
2227 break;
2228
2230 if(!stream->read_tag(t_pTag, pos))
2231 goto bad;
2232 *id = *(fiffId)t_pTag->data();
2233 break;
2234
2235 case FIFF_COORD_TRANS :
2236 if(!stream->read_tag(t_pTag, pos))
2237 goto bad;
2238 t = FiffCoordTrans::readFromTag( t_pTag );
2239 if (!t.isEmpty() && (t.from != FIFFV_COORD_DEVICE || t.to != FIFFV_COORD_HEAD))
2240 {
2241 t = FiffCoordTrans();
2242 }
2243 break;
2244
2245 case FIFF_CH_INFO : /* Information about one channel */
2246 if(!stream->read_tag(t_pTag, pos))
2247 goto bad;
2248 this_ch = t_pTag->toChInfo();
2249 if (this_ch.scanNo <= 0 || this_ch.scanNo > nchan) {
2250 printf ("FIFF_CH_INFO : scan # out of range %d (%d)!",this_ch.scanNo,nchan);
2251 goto bad;
2252 }
2253 else
2254 chs[this_ch.scanNo-1] = this_ch;
2255 to_find--;
2256 break;
2257 }
2258 }
2259 if (to_find != 0) {
2260 qCritical("Some of the channel information was missing.");
2261 goto bad;
2262 }
2263 if (t.isEmpty() && meg_head_t != NULL) {
2264 /*
2265 * Try again in a more general fashion
2266 */
2268 if (t.isEmpty()) {
2269 qCritical("MEG -> head coordinate transformation not found.");
2270 goto bad;
2271 }
2272 }
2273 /*
2274 * Sort out the channels
2275 */
2276 for (k = 0; k < nchan; k++) {
2277 if (chs[k].kind == FIFFV_MEG_CH) {
2278 meg.append(chs[k]);
2279 nmeg++;
2280 } else if (chs[k].kind == FIFFV_REF_MEG_CH) {
2281 meg_comp.append(chs[k]);
2282 nmeg_comp++;
2283 } else if (chs[k].kind == FIFFV_EEG_CH) {
2284 eeg.append(chs[k]);
2285 neeg++;
2286 }
2287 }
2288
2289 stream->close();
2290
2291 megp = meg;
2292 if(nmegp) {
2293 *nmegp = nmeg;
2294 }
2295
2296 meg_compp = meg_comp;
2297 *nmeg_compp = nmeg_comp;
2298
2299 eegp = eeg;
2300 *neegp = neeg;
2301
2302 if (idp == NULL) {
2303 FREE_3(id);
2304 }
2305 else
2306 *idp = id;
2307 if (meg_head_t == NULL) {
2308 ; // value type, no cleanup needed
2309 }
2310 else
2311 *meg_head_t = std::move(t);
2312
2313 return FIFF_OK;
2314
2315bad : {
2316
2317 stream->close();
2318 FREE_3(id);
2319
2320 return FIFF_FAIL;
2321 }
2322}
2323
2324//============================= data.c =============================
2325
2326#if defined(_WIN32) || defined(_WIN64)
2327#define snprintf _snprintf
2328#define vsnprintf _vsnprintf
2329#define strcasecmp _stricmp
2330#define strncasecmp _strnicmp
2331#endif
2332
2333int is_selected_in_data(mshMegEegData d, const QString& ch_name)
2334/*
2335 * Is this channel selected in data
2336 */
2337{
2338 int issel = FALSE;
2339 int k;
2340
2341 for (k = 0; k < d->meas->nchan; k++)
2342 if (QString::compare(ch_name,d->meas->chs[k].ch_name,Qt::CaseInsensitive) == 0) {
2343 issel = d->sels[k];
2344 break;
2345 }
2346 return issel;
2347}
2348
2349//============================= mne_process_bads.c =============================
2350
2351static int whitespace_3(char *text)
2352
2353{
2354 if (text == NULL || strlen(text) == 0)
2355 return TRUE;
2356 if (strspn(text," \t\n\r") == strlen(text))
2357 return TRUE;
2358 return FALSE;
2359}
2360
2361static char *next_line_3(char *line, int n, FILE *in)
2362{
2363 char *res;
2364
2365 for (res = fgets(line,n,in); res != NULL; res = fgets(line,n,in))
2366 if (!whitespace_3(res))
2367 if (res[0] != '#')
2368 break;
2369 return res;
2370}
2371
2372#define MAXLINE 500
2373
2374int mne_read_bad_channels_3(const QString& name, QStringList& listp, int& nlistp)
2375/*
2376 * Read bad channel names
2377 */
2378{
2379 FILE *in = NULL;
2380 QStringList list;
2381 char line[MAXLINE+1];
2382 char *next;
2383
2384 if (name.isEmpty())
2385 return OK;
2386
2387 if ((in = fopen(name.toUtf8().data(),"r")) == NULL) {
2388 qCritical() << name;
2389 goto bad;
2390 }
2391 while ((next = next_line_3(line,MAXLINE,in)) != NULL) {
2392 if (strlen(next) > 0) {
2393 if (next[strlen(next)-1] == '\n')
2394 next[strlen(next)-1] = '\0';
2395 list.append(next);
2396 }
2397 }
2398 if (ferror(in))
2399 goto bad;
2400
2401 listp = list;
2402 nlistp = list.size();
2403
2404 return OK;
2405
2406bad : {
2407 list.clear();
2408 if (in != NULL)
2409 fclose(in);
2410 return FAIL;
2411 }
2412}
2413
2415 const FiffDirNode::SPtr& pNode,
2416 QStringList& listp,
2417 int& nlistp)
2418{
2419 FiffDirNode::SPtr node,bad;
2420 QList<FiffDirNode::SPtr> temp;
2421 QStringList list;
2422 int nlist = 0;
2423 FiffTag::SPtr t_pTag;
2424 QString names;
2425
2426 if (pNode->isEmpty())
2427 node = stream->dirtree();
2428 else
2429 node = pNode;
2430
2431 temp = node->dir_tree_find(FIFFB_MNE_BAD_CHANNELS);
2432 if (temp.size() > 0) {
2433 bad = temp[0];
2434
2435 bad->find_tag(stream, FIFF_MNE_CH_NAME_LIST, t_pTag);
2436 if (t_pTag) {
2437 names = t_pTag->toString();
2438 mne_string_to_name_list_3(names,list,nlist);
2439 }
2440 }
2441 listp = list;
2442 nlistp = list.size();
2443 return OK;
2444}
2445
2446int mne_read_bad_channel_list_3(const QString& name, QStringList& listp, int& nlistp)
2447
2448{
2449 QFile file(name);
2450 FiffStream::SPtr stream(new FiffStream(&file));
2451
2452 int res;
2453
2454 if(!stream->open())
2455 return FAIL;
2456
2457 res = mne_read_bad_channel_list_from_node_3(stream,stream->dirtree(),listp,nlistp);
2458
2459 stream->close();
2460
2461 return res;
2462}
2463
2464std::unique_ptr<MNECovMatrix> mne_read_cov(const QString& name,int kind)
2465/*
2466 * Read a covariance matrix from a fiff
2467 */
2468{
2469 QFile file(name);
2470 FiffStream::SPtr stream(new FiffStream(&file));
2471
2472 FiffTag::SPtr t_pTag;
2473 QList<FiffDirNode::SPtr> nodes;
2474 FiffDirNode::SPtr covnode;
2475
2476 QStringList names; /* Optional channel name list */
2477 int nnames = 0;
2478 Eigen::VectorXd cov;
2479 Eigen::VectorXd cov_diag;
2480 FiffSparseMatrix* cov_sparse = NULL;
2481 Eigen::VectorXd lambda;
2482 Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> eigen;
2483 MatrixXf tmp_eigen;
2484 QStringList bads;
2485 int nbad = 0;
2486 int ncov = 0;
2487 int nfree = 1;
2488 std::unique_ptr<MNECovMatrix> res;
2489
2490 int k,p,nn;
2491 float *f;
2492 double *d;
2493 MNEProjOp* op = NULL;
2494 MNESssData* sss = NULL;
2495
2496 if(!stream->open())
2497 goto out;
2498
2499 nodes = stream->dirtree()->dir_tree_find(FIFFB_MNE_COV);
2500
2501 if (nodes.size() == 0) {
2502 printf("No covariance matrix available in %s",name.toUtf8().data());
2503 goto out;
2504 }
2505 /*
2506 * Locate the desired matrix
2507 */
2508 for (k = 0 ; k < nodes.size(); ++k) {
2509 if (!nodes[k]->find_tag(stream, FIFF_MNE_COV_KIND, t_pTag))
2510 continue;
2511
2512 if (*t_pTag->toInt() == kind) {
2513 covnode = nodes[k];
2514 break;
2515 }
2516 }
2517 if (covnode->isEmpty()) {
2518 printf("Desired covariance matrix not found from %s",name.toUtf8().data());
2519 goto out;
2520 }
2521 /*
2522 * Read the data
2523 */
2524 if (!nodes[k]->find_tag(stream, FIFF_MNE_COV_DIM, t_pTag))
2525 goto out;
2526 ncov = *t_pTag->toInt();
2527
2528 if (nodes[k]->find_tag(stream, FIFF_MNE_COV_NFREE, t_pTag)) {
2529 nfree = *t_pTag->toInt();
2530 }
2531 if (covnode->find_tag(stream, FIFF_MNE_ROW_NAMES, t_pTag)) {
2532 mne_string_to_name_list_3(t_pTag->toString(),names,nnames);
2533 if (nnames != ncov) {
2534 qCritical("Incorrect number of channel names for a covariance matrix");
2535 goto out;
2536 }
2537 }
2538 if (!nodes[k]->find_tag(stream, FIFF_MNE_COV, t_pTag)) {
2539 if (!nodes[k]->find_tag(stream, FIFF_MNE_COV_DIAG, t_pTag))
2540 goto out;
2541 else {
2542 if (t_pTag->getType() == FIFFT_DOUBLE) {
2543 cov_diag.resize(ncov);
2544 qDebug() << "ToDo: Check whether cov_diag contains the right stuff!!! - use VectorXd instead";
2545 d = t_pTag->toDouble();
2546 for (p = 0; p < ncov; p++)
2547 cov_diag[p] = d[p];
2548 if (check_cov_data(cov_diag.data(),ncov) != OK)
2549 goto out;
2550 }
2551 else if (t_pTag->getType() == FIFFT_FLOAT) {
2552 cov_diag.resize(ncov);
2553 qDebug() << "ToDo: Check whether f contains the right stuff!!! - use VectorXf instead";
2554 f = t_pTag->toFloat();
2555 for (p = 0; p < ncov; p++)
2556 cov_diag[p] = f[p];
2557 }
2558 else {
2559 printf("Illegal data type for covariance matrix");
2560 goto out;
2561 }
2562 }
2563 }
2564 else {
2565 nn = ncov*(ncov+1)/2;
2566 if (t_pTag->getType() == FIFFT_DOUBLE) {
2567 qDebug() << "ToDo: Check whether cov contains the right stuff!!! - use VectorXd instead";
2568// qDebug() << t_pTag->size() / sizeof(double);
2569 cov.resize(nn);
2570 d = t_pTag->toDouble();
2571 for (p = 0; p < nn; p++)
2572 cov[p] = d[p];
2573 if (check_cov_data(cov.data(),nn) != OK)
2574 goto out;
2575 }
2576 else if (t_pTag->getType() == FIFFT_FLOAT) {
2577 cov.resize(nn);
2578 f = t_pTag->toFloat();
2579 for (p = 0; p < nn; p++)
2580 cov[p] = f[p];
2581 }
2582 else {
2583 auto cov_sparse_uptr = FiffSparseMatrix::fiff_get_float_sparse_matrix(t_pTag);
2584 if (!cov_sparse_uptr)
2585 goto out;
2586 cov_sparse = cov_sparse_uptr.release();
2587 }
2588
2589 if (nodes[k]->find_tag(stream, FIFF_MNE_COV_EIGENVALUES, t_pTag)) {
2590 const double *lambda_data = (const double *)t_pTag->toDouble();
2591 lambda = Eigen::Map<const Eigen::VectorXd>(lambda_data, ncov);
2592 if (nodes[k]->find_tag(stream, FIFF_MNE_COV_EIGENVECTORS, t_pTag))
2593 goto out;
2594
2595 tmp_eigen = t_pTag->toFloatMatrix().transpose();
2596 eigen.resize(tmp_eigen.rows(),tmp_eigen.cols());
2597 for (int r = 0; r < tmp_eigen.rows(); ++r)
2598 for (int c = 0; c < tmp_eigen.cols(); ++c)
2599 eigen(r,c) = tmp_eigen(r,c);
2600 }
2601 /*
2602 * Read the optional projection operator
2603 */
2604 if ((op = mne_read_proj_op_from_node_3(stream,nodes[k])) == NULL)
2605 goto out;
2606 /*
2607 * Read the optional SSS data
2608 */
2609 if ((sss = MNESssData::read_from_node(stream,nodes[k])) == NULL)
2610 goto out;
2611 /*
2612 * Read the optional bad channel list
2613 */
2614 if (mne_read_bad_channel_list_from_node_3(stream,nodes[k],bads,nbad) == FAIL)
2615 goto out;
2616 }
2617 if (cov_sparse)
2618 res = MNECovMatrix::create_sparse(kind,ncov,names,cov_sparse);
2619 else if (cov.size() > 0)
2620 res = MNECovMatrix::create_dense(kind,ncov,names,cov);
2621 else if (cov_diag.size() > 0)
2622 res = MNECovMatrix::create_diag(kind,ncov,names,cov_diag);
2623 else {
2624 qCritical("mne_read_cov : covariance matrix data is not defined. How come?");
2625 goto out;
2626 }
2627 cov_sparse = NULL;
2628 res->eigen = std::move(eigen);
2629 res->lambda = std::move(lambda);
2630 res->nfree = nfree;
2631 res->bads = bads;
2632 res->nbad = nbad;
2633 /*
2634 * Count the non-zero eigenvalues
2635 */
2636 if (res->lambda.size() > 0) {
2637 res->nzero = 0;
2638 for (k = 0; k < res->ncov; k++, res->nzero++)
2639 if (res->lambda[k] > 0)
2640 break;
2641 }
2642
2643 if (op && op->nitems > 0) {
2644 res->proj.reset(op);
2645 op = NULL;
2646 }
2647 if (sss && sss->comp_info.size() > 0 && sss->job != FIFFV_SSS_JOB_NOTHING) {
2648 res->sss.reset(sss);
2649 sss = NULL;
2650 }
2651
2652out : {
2653 stream->close();
2654 if(op)
2655 delete op;
2656 if(sss)
2657 delete sss;
2658
2659 if (!res) {
2660 names.clear();
2661 bads.clear();
2662 if(cov_sparse)
2663 delete cov_sparse;
2664 }
2665 return res;
2666 }
2667}
2668
2669//============================= mne_coord_transforms.c =============================
2670
2671namespace MNELIB
2672{
2673
2677typedef struct {
2679 const char *name;
2681
2682}
2683
2684const char *mne_coord_frame_name_3(int frame)
2685
2686{
2687 static frameNameRec_3 frames[] = {
2688 {FIFFV_COORD_UNKNOWN,"unknown"},
2689 {FIFFV_COORD_DEVICE,"MEG device"},
2690 {FIFFV_COORD_ISOTRAK,"isotrak"},
2691 {FIFFV_COORD_HPI,"hpi"},
2692 {FIFFV_COORD_HEAD,"head"},
2693 {FIFFV_COORD_MRI,"MRI (surface RAS)"},
2694 {FIFFV_MNE_COORD_MRI_VOXEL, "MRI voxel"},
2695 {FIFFV_COORD_MRI_SLICE,"MRI slice"},
2696 {FIFFV_COORD_MRI_DISPLAY,"MRI display"},
2697 {FIFFV_MNE_COORD_CTF_DEVICE,"CTF MEG device"},
2698 {FIFFV_MNE_COORD_CTF_HEAD,"CTF/4D/KIT head"},
2699 {FIFFV_MNE_COORD_RAS,"RAS (non-zero origin)"},
2700 {FIFFV_MNE_COORD_MNI_TAL,"MNI Talairach"},
2701 {FIFFV_MNE_COORD_FS_TAL_GTZ,"Talairach (MNI z > 0)"},
2702 {FIFFV_MNE_COORD_FS_TAL_LTZ,"Talairach (MNI z < 0)"},
2703 {-1,"unknown"}
2704 };
2705 int k;
2706 for (k = 0; frames[k].frame != -1; k++) {
2707 if (frame == frames[k].frame)
2708 return frames[k].name;
2709 }
2710 return frames[k].name;
2711}
2712
2713//============================= mne_read_process_forward_solution.c =============================
2714
2715void mne_merge_channels(const QList<FiffChInfo>& chs1,
2716 int nch1,
2717 const QList<FiffChInfo>& chs2,
2718 int nch2,
2719 QList<FiffChInfo>& resp,
2720 int *nresp)
2721
2722{
2723 resp.clear();
2724 resp.reserve(nch1+nch2);
2725
2726 int k;
2727 for (k = 0; k < nch1; k++) {
2728 resp.append(chs1.at(k));
2729 }
2730 for (k = 0; k < nch2; k++) {
2731 resp.append(chs2.at(k));
2732 }
2733
2734 *nresp = nch1+nch2;
2735 return;
2736}
2737
2738//============================= read_ch_info.c =============================
2739
2740static FiffDirNode::SPtr find_meas_3 (const FiffDirNode::SPtr& node)
2741/*
2742 * Find corresponding meas node
2743 */
2744{
2745 FiffDirNode::SPtr empty_node;
2746 FiffDirNode::SPtr tmp_node = node;
2747
2748 while (tmp_node->type != FIFFB_MEAS) {
2749 if (tmp_node->parent == NULL)
2750 return empty_node;//(NULL);
2751 tmp_node = tmp_node->parent;
2752 }
2753 return (tmp_node);
2754}
2755
2756static FiffDirNode::SPtr find_meas_info_3 (const FiffDirNode::SPtr& node)
2757/*
2758 * Find corresponding meas info node
2759 */
2760{
2761 int k;
2762 FiffDirNode::SPtr empty_node;
2763 FiffDirNode::SPtr tmp_node = node;
2764
2765 while (tmp_node->type != FIFFB_MEAS) {
2766 if (tmp_node->parent == NULL)
2767 return empty_node;
2768 tmp_node = tmp_node->parent;
2769 }
2770 for (k = 0; k < tmp_node->nchild(); k++)
2771 if (tmp_node->children[k]->type == FIFFB_MEAS_INFO)
2772 return (tmp_node->children[k]);
2773 return empty_node;
2774}
2775
2776static int get_all_chs (//fiffFile file, /* The file we are reading */
2777 FiffStream::SPtr& stream,
2778 const FiffDirNode::SPtr& p_node, /* The directory node containing our data */
2779 fiffId *id, /* The block id from the nearest FIFFB_MEAS parent */
2780 QList<FiffChInfo>& chp, /* Channel descriptions */
2781 int *nchanp) /* Number of channels */
2782/*
2783 * Find channel information from
2784 * nearest FIFFB_MEAS_INFO parent of
2785 * node.
2786 */
2787{
2788 QList<FiffChInfo> ch;
2789 FiffChInfo this_ch;
2790 int j,k;
2791 int nchan = 0;
2792 int to_find = 0;
2793 FiffDirNode::SPtr meas;
2794 FiffDirNode::SPtr meas_info;
2795 fiff_int_t kind, pos;
2796 FiffTag::SPtr t_pTag;
2797
2798 *id = NULL;
2799 /*
2800 * Find desired parents
2801 */
2802 if (!(meas = find_meas_3(p_node))) {
2803 qCritical("Meas. block not found!");
2804 goto bad;
2805 }
2806
2807 if (!(meas_info = find_meas_info_3(p_node))) {
2808 qCritical ("Meas. info not found!");
2809 goto bad;
2810 }
2811 /*
2812 * Is there a block id is in the FIFFB_MEAS node?
2813 */
2814 if (!meas->id.isEmpty()) {
2815 *id = MALLOC_3(1,fiffIdRec);
2816 (*id)->version = meas->id.version;
2817 (*id)->machid[0] = meas->id.machid[0];
2818 (*id)->machid[1] = meas->id.machid[1];
2819 (*id)->time = meas->id.time;
2820 }
2821 /*
2822 * Others from FIFFB_MEAS_INFO
2823 */
2824 for (k = 0; k < meas_info->nent(); k++) {
2825 kind = meas_info->dir[k]->kind;
2826 pos = meas_info->dir[k]->pos;
2827 switch (kind) {
2828 case FIFF_NCHAN :
2829 if (!stream->read_tag(t_pTag,pos))
2830 goto bad;
2831 nchan = *t_pTag->toInt();
2832 *nchanp = nchan;
2833
2834 for (j = 0; j < nchan; j++) {
2835 ch.append(FiffChInfo());
2836 ch[j].scanNo = -1;
2837 }
2838
2839 to_find += nchan - 1;
2840 break;
2841
2842 case FIFF_CH_INFO : /* Information about one channel */
2843 if (!stream->read_tag(t_pTag,pos))
2844 goto bad;
2845 this_ch = t_pTag->toChInfo();
2846 if (this_ch.scanNo <= 0 || this_ch.scanNo > nchan) {
2847 qCritical ("FIFF_CH_INFO : scan # out of range!");
2848 goto bad;
2849 }
2850 else
2851 ch[this_ch.scanNo-1] = this_ch;
2852 to_find--;
2853 break;
2854 }
2855 }
2856
2857 chp = ch;
2858 return FIFF_OK;
2859
2860bad : {
2861 return FIFF_FAIL;
2862 }
2863}
2864
2865static int read_ch_info(const QString& name,
2866 QList<FiffChInfo>& chsp,
2867 int *nchanp,
2868 fiffId *idp)
2869/*
2870 * Read channel information from a measurement file
2871 */
2872{
2873 QFile file(name);
2874 FiffStream::SPtr stream(new FiffStream(&file));
2875
2876 QList<FiffChInfo> chs;
2877 int nchan = 0;
2878 fiffId id = NULL;
2879
2880 QList<FiffDirNode::SPtr> meas;
2881 FiffDirNode::SPtr node;
2882
2883 if(!stream->open())
2884 goto bad;
2885
2886 meas = stream->dirtree()->dir_tree_find(FIFFB_MEAS);
2887 if (meas.size() == 0) {
2888 qCritical ("%s : no MEG data available here",name.toUtf8().data());
2889 goto bad;
2890 }
2891 node = meas[0];
2892 if (get_all_chs(stream,
2893 node,
2894 &id,
2895 chs,
2896 &nchan) == FIFF_FAIL)
2897 goto bad;
2898 chsp = chs;
2899 *nchanp = nchan;
2900 *idp = id;
2901 stream->close();
2902 return FIFF_OK;
2903
2904bad : {
2905 FREE_3(id);
2906 stream->close();
2907 return FIFF_FAIL;
2908 }
2909}
2910
2911#define TOO_CLOSE 1e-4
2912
2913static int at_origin (const Eigen::Vector3f& rr)
2914{
2915 return (rr.norm() < TOO_CLOSE);
2916}
2917
2918static int is_valid_eeg_ch(const FiffChInfo& ch)
2919/*
2920 * Is the electrode position information present?
2921 */
2922{
2923 if (ch.kind == FIFFV_EEG_CH) {
2924 if (at_origin(ch.chpos.r0) ||
2926 return FALSE;
2927 else
2928 return TRUE;
2929 }
2930 return FALSE;
2931}
2932
2933static int accept_ch(const FiffChInfo& ch,
2934 const QStringList& bads,
2935 int nbad)
2936
2937{
2938 int k;
2939 for (k = 0; k < nbad; k++)
2940 if (QString::compare(ch.ch_name,bads[k]) == 0)
2941 return FALSE;
2942 return TRUE;
2943}
2944
2945int read_meg_eeg_ch_info(const QString& name, /* Input file */
2946 int do_meg, /* Use MEG */
2947 int do_eeg, /* Use EEG */
2948 const QStringList& bads, /* List of bad channels */
2949 int nbad,
2950 QList<FiffChInfo>& chsp, /* MEG + EEG channels */
2951 int *nmegp, /* Count of each */
2952 int *neegp)
2953/*
2954 * Read the channel information and split it into two arrays,
2955 * one for MEG and one for EEG
2956 */
2957{
2958 QList<FiffChInfo> chs;
2959 int nchan = 0;
2960 QList<FiffChInfo> meg;
2961 int nmeg = 0;
2962 QList<FiffChInfo> eeg;
2963 int neeg = 0;
2964 fiffId id = NULL;
2965 int nch;
2966
2967 int k;
2968
2969 if (read_ch_info(name,
2970 chs,
2971 &nchan,
2972 &id) != FIFF_OK)
2973 goto bad;
2974 /*
2975 * Sort out the channels
2976 */
2977 for (k = 0; k < nchan; k++) {
2978 if (accept_ch(chs[k],bads,nbad)) {
2979 if (do_meg && chs[k].kind == FIFFV_MEG_CH) {
2980 meg.append(chs[k]);
2981 nmeg++;
2982 } else if (do_eeg && chs[k].kind == FIFFV_EEG_CH && is_valid_eeg_ch(chs[k])) {
2983 eeg.append(chs[k]);
2984 neeg++;
2985 }
2986 }
2987 }
2988
2990 nmeg,
2991 eeg,
2992 neeg,
2993 chsp,
2994 &nch);
2995
2996 if(nmegp) {
2997 *nmegp = nmeg;
2998 }
2999 if(neegp) {
3000 *neegp = neeg;
3001 }
3002 FREE_3(id);
3003 return FIFF_OK;
3004
3005bad : {
3006 FREE_3(id);
3007 return FIFF_FAIL;
3008 }
3009}
3010
3012/*
3013 * Pick the diagonal elements of the full covariance matrix
3014 */
3015{
3016 int k,p;
3017 if (c->cov.size() == 0)
3018 return;
3019#define REALLY_REVERT
3020#ifdef REALLY_REVERT
3021 c->cov_diag.resize(c->ncov);
3022
3023 for (k = p = 0; k < c->ncov; k++) {
3024 c->cov_diag[k] = c->cov[p];
3025 p = p + k + 2;
3026 }
3027 c->cov.resize(0);
3028#else
3029 for (j = 0, p = 0; j < c->ncov; j++)
3030 for (k = 0; k <= j; k++, p++)
3031 if (j != k)
3032 c->cov[p] = 0.0;
3033 else
3034#endif
3035 c->lambda.resize(0);
3036 c->eigen.resize(0,0);
3037 return;
3038}
3039
3040std::unique_ptr<MNECovMatrix> mne_pick_chs_cov_omit(MNECovMatrix* c,
3041 const QStringList& new_names,
3042 int ncov,
3043 int omit_meg_eeg,
3044 const QList<FiffChInfo>& chs)
3045/*
3046 * Pick designated channels from a covariance matrix, optionally omit MEG/EEG correlations
3047 */
3048{
3049 int j,k;
3050 int *pick = NULL;
3051 Eigen::VectorXd cov_local;
3052 Eigen::VectorXd cov_diag_local;
3053 QStringList names;
3054 int *is_meg = NULL;
3055 int from,to;
3056 std::unique_ptr<MNECovMatrix> res;
3057
3058 if (ncov == 0) {
3059 qCritical("No channels specified for picking in mne_pick_chs_cov_omit");
3060 return nullptr;
3061 }
3062 if (c->names.isEmpty()) {
3063 qCritical("No names in covariance matrix. Cannot do picking.");
3064 return nullptr;
3065 }
3066 pick = MALLOC_3(ncov,int);
3067 for (j = 0; j < ncov; j++)
3068 pick[j] = -1;
3069 for (j = 0; j < ncov; j++)
3070 for (k = 0; k < c->ncov; k++)
3071 if (QString::compare(c->names[k],new_names[j]) == 0) {
3072 pick[j] = k;
3073 break;
3074 }
3075 for (j = 0; j < ncov; j++) {
3076 if (pick[j] < 0) {
3077 printf("All desired channels not found in the covariance matrix (at least missing %s).", new_names[j].toUtf8().constData());
3078 FREE_3(pick);
3079 return nullptr;
3080 }
3081 }
3082 if (omit_meg_eeg) {
3083 is_meg = MALLOC_3(ncov,int);
3084 if (!chs.isEmpty()) {
3085 for (j = 0; j < ncov; j++)
3086 if (chs[j].kind == FIFFV_MEG_CH)
3087 is_meg[j] = TRUE;
3088 else
3089 is_meg[j] = FALSE;
3090 }
3091 else {
3092 for (j = 0; j < ncov; j++)
3093 if (new_names[j].startsWith("MEG"))
3094 is_meg[j] = TRUE;
3095 else
3096 is_meg[j] = FALSE;
3097 }
3098 }
3099 if (c->cov_diag.size() > 0) {
3100 cov_diag_local.resize(ncov);
3101 for (j = 0; j < ncov; j++) {
3102 cov_diag_local[j] = c->cov_diag[pick[j]];
3103 names.append(c->names[pick[j]]);
3104 }
3105 }
3106 else {
3107 cov_local.resize(ncov*(ncov+1)/2);
3108 for (j = 0; j < ncov; j++) {
3109 names.append(c->names[pick[j]]);
3110 for (k = 0; k <= j; k++) {
3111 from = mne_lt_packed_index_3(pick[j],pick[k]);
3112 to = mne_lt_packed_index_3(j,k);
3113 if (to < 0 || to > ncov*(ncov+1)/2-1) {
3114 printf("Wrong destination index in mne_pick_chs_cov : %d %d %d\n",j,k,to);
3115 exit(1);
3116 }
3117 if (from < 0 || from > c->ncov*(c->ncov+1)/2-1) {
3118 printf("Wrong source index in mne_pick_chs_cov : %d %d %d\n",pick[j],pick[k],from);
3119 exit(1);
3120 }
3121 cov_local[to] = c->cov[from];
3122 if (omit_meg_eeg)
3123 if (is_meg[j] != is_meg[k])
3124 cov_local[to] = 0.0;
3125 }
3126 }
3127 }
3128
3129 res = MNECovMatrix::create(c->kind,ncov,names,cov_local,cov_diag_local);
3130
3131 res->bads = c->bads;
3132 res->nbad = c->nbad;
3133 res->proj.reset(c->proj ? c->proj->dup() : nullptr);
3134 res->sss.reset(c->sss ? new MNESssData(*(c->sss)) : nullptr);
3135
3136 if (c->ch_class.size() > 0) {
3137 res->ch_class.resize(res->ncov);
3138 for (k = 0; k < res->ncov; k++)
3139 res->ch_class[k] = c->ch_class[pick[k]];
3140 }
3141 FREE_3(pick);
3142 FREE_3(is_meg);
3143 return res;
3144}
3145
3146int mne_proj_op_proj_dvector(MNEProjOp* op, double *vec, int nch, int do_complement)
3147/*
3148 * Apply projection operator to a vector (doubles)
3149 * Assume that all dimension checking etc. has been done before
3150 */
3151{
3152 float *pvec;
3153 double w;
3154 int k,p;
3155
3156 if (op->nvec <= 0)
3157 return OK;
3158
3159 if (op->nch != nch) {
3160 qCritical("Data vector size does not match projection operator");
3161 return FAIL;
3162 }
3163
3164 Eigen::VectorXd res = Eigen::VectorXd::Zero(op->nch);
3165
3166 for (p = 0; p < op->nvec; p++) {
3167 pvec = op->proj_data.row(p).data();
3168 w = 0.0;
3169 for (k = 0; k < op->nch; k++)
3170 w += vec[k]*pvec[k];
3171 for (k = 0; k < op->nch; k++)
3172 res[k] = res[k] + w*pvec[k];
3173 }
3174
3175 if (do_complement) {
3176 for (k = 0; k < op->nch; k++)
3177 vec[k] = vec[k] - res[k];
3178 }
3179 else {
3180 for (k = 0; k < op->nch; k++)
3181 vec[k] = res[k];
3182 }
3183
3184 return OK;
3185}
3186
3187int mne_name_list_match(const QStringList& list1, int nlist1,
3188 const QStringList& list2, int nlist2)
3189/*
3190 * Check whether two name lists are identical
3191 */
3192{
3193 int k;
3194 if (list1.isEmpty() && list2.isEmpty())
3195 return 0;
3196 if (list1.isEmpty() || list2.isEmpty())
3197 return 1;
3198 if (nlist1 != nlist2)
3199 return 1;
3200 for (k = 0; k < nlist1; k++)
3201 if (QString::compare(list1[k],list2[k]) != 0)
3202 return 1;
3203 return 0;
3204}
3205
3206void mne_transpose_dsquare(double **mat, int n)
3207/*
3208 * In-place transpose of a square matrix
3209 */
3210{
3211 int j,k;
3212 double val;
3213
3214 for (j = 1; j < n; j++)
3215 for (k = 0; k < j; k++) {
3216 val = mat[j][k];
3217 mat[j][k] = mat[k][j];
3218 mat[k][j] = val;
3219 }
3220 return;
3221}
3222
3224/*
3225 * Apply the projection operator to a covariance matrix
3226 */
3227{
3228 double **dcov = NULL;
3229 int j,k,p;
3230 int do_complement = TRUE;
3231
3232 if (op == NULL || op->nitems == 0)
3233 return OK;
3234
3235 if (mne_name_list_match(op->names,op->nch,c->names,c->ncov) != OK) {
3236 qCritical("Incompatible data in mne_proj_op_apply_cov");
3237 return FAIL;
3238 }
3239
3240 dcov = ALLOC_DCMATRIX_3(c->ncov,c->ncov);
3241 /*
3242 * Return the appropriate result
3243 */
3244 if (c->cov_diag.size() > 0) { /* Pick the diagonals */
3245 for (j = 0, p = 0; j < c->ncov; j++)
3246 for (k = 0; k < c->ncov; k++)
3247 dcov[j][k] = (j == k) ? c->cov_diag[j] : 0;
3248 }
3249 else { /* Return full matrix */
3250 for (j = 0, p = 0; j < c->ncov; j++)
3251 for (k = 0; k <= j; k++)
3252 dcov[j][k] = c->cov[p++];
3253 for (j = 0; j < c->ncov; j++)
3254 for (k = j+1; k < c->ncov; k++)
3255 dcov[j][k] = dcov[k][j];
3256 }
3257
3258 /*
3259 * Project from front and behind
3260 */
3261 for (k = 0; k < c->ncov; k++) {
3262 if (mne_proj_op_proj_dvector(op,dcov[k],c->ncov,do_complement) != OK)
3263 return FAIL;
3264 }
3265
3266 mne_transpose_dsquare(dcov,c->ncov);
3267
3268 for (k = 0; k < c->ncov; k++)
3269 if (mne_proj_op_proj_dvector(op,dcov[k],c->ncov,do_complement) != OK)
3270 return FAIL;
3271
3272 /*
3273 * Return the result
3274 */
3275 if (c->cov_diag.size() > 0) { /* Pick the diagonal elements */
3276 for (j = 0; j < c->ncov; j++) {
3277 c->cov_diag[j] = dcov[j][j];
3278 }
3279 c->cov.resize(0);
3280 }
3281 else { /* Put everything back */
3282 for (j = 0, p = 0; j < c->ncov; j++)
3283 for (k = 0; k <= j; k++)
3284 c->cov[p++] = dcov[j][k];
3285 }
3286
3287 FREE_DCMATRIX_3(dcov);
3288
3289 c->nproj = op->affect(c->names,c->ncov);
3290 return OK;
3291}
3292
3293//=============================================================================================================
3294// DEFINE MEMBER METHODS
3295//=============================================================================================================
3296
3299, nmeg (0)
3300, neeg (0)
3301, sphere_funcs (NULL)
3302, bem_funcs (NULL)
3303, funcs (NULL)
3304, mag_dipole_funcs (NULL)
3306, nave (1)
3309, user (NULL)
3310{
3311 r0[0] = 0.0f;
3312 r0[1] = 0.0f;
3313 r0[2] = 0.0f;
3314}
3315
3316//=============================================================================================================
3317
3319{
3320 // unique_ptr members (pick, meg_coils, eeg_els, eeg_model, bem_model, noise_orig, noise, proj) auto-cleanup
3321
3322 free_dipole_fit_funcs(sphere_funcs);
3323 free_dipole_fit_funcs(bem_funcs);
3324 free_dipole_fit_funcs(mag_dipole_funcs);
3325}
3326
3327//=============================================================================================================
3328
3330/*
3331 * Take care of some hairy details
3332 */
3333{
3334 FwdCompData* comp;
3336 int fit_sphere_to_bem = TRUE;
3337
3338 if (!d->bemname.isEmpty()) {
3339 /*
3340 * Set up the boundary-element model
3341 */
3342 QString bemsolname = FwdBemModel::fwd_bem_make_bem_sol_name(d->bemname);
3343 d->bemname = bemsolname;
3344
3345 printf("\nSetting up the BEM model using %s...\n",d->bemname.toUtf8().constData());
3346 printf("\nLoading surfaces...\n");
3348 if (d->bem_model) {
3349 printf("Three-layer model surfaces loaded.\n");
3350 }
3351 else {
3353 if (!d->bem_model)
3354 goto out;
3355 printf("Homogeneous model surface loaded.\n");
3356 }
3357 if (d->neeg > 0 && d->bem_model->nsurf == 1) {
3358 qCritical("Cannot use a homogeneous model in EEG calculations.");
3359 goto out;
3360 }
3361 printf("\nLoading the solution matrix...\n");
3363 goto out;
3364 printf("Employing the head->MRI coordinate transform with the BEM model.\n");
3365 Q_ASSERT(d->mri_head_t);
3367 goto out;
3368 printf("BEM model %s is now set up\n",d->bem_model->sol_name.toUtf8().constData());
3369 /*
3370 * Find the best-fitting sphere
3371 */
3372 if (fit_sphere_to_bem) {
3373 MNESurface* inner_skull;
3374 float simplex_size = 2e-2;
3375 float R;
3376
3377 if ((inner_skull = d->bem_model->fwd_bem_find_surface(FIFFV_BEM_SURF_ID_BRAIN)) == NULL)
3378 goto out;
3379
3380 if (fit_sphere_to_points(inner_skull->rr,inner_skull->np,simplex_size,d->r0,&R) == FAIL)
3381 goto out;
3382
3384 printf("Fitted sphere model origin : %6.1f %6.1f %6.1f mm rad = %6.1f mm.\n",
3385 1000*d->r0[X_3],1000*d->r0[Y_3],1000*d->r0[Z_3],1000*R);
3386 }
3387 d->bem_funcs = f = new_dipole_fit_funcs();
3388 if (d->nmeg > 0) {
3389 /*
3390 * Use the new compensated field computation
3391 * It works the same way independent of whether or not the compensation is in effect
3392 */
3393 comp = FwdCompData::fwd_make_comp_data(comp_data,d->meg_coils.get(),comp_coils,
3394 FwdBemModel::fwd_bem_field,NULL,NULL,d->bem_model.get(),NULL);
3395 if (!comp)
3396 goto out;
3397 printf("Compensation setup done.\n");
3398
3399 printf("MEG solution matrix...");
3401 goto out;
3403 goto out;
3404 printf("[done]\n");
3405
3407 f->meg_vec_field = NULL;
3408 f->meg_client = comp;
3410 }
3411 if (d->neeg > 0) {
3412 printf("\tEEG solution matrix...");
3413 if (FwdBemModel::fwd_bem_specify_els(d->bem_model.get(),d->eeg_els.get()) == FAIL)
3414 goto out;
3415 printf("[done]\n");
3417 f->eeg_vec_pot = NULL;
3418 f->eeg_client = d->bem_model.get();
3419 }
3420 }
3421 if (d->neeg > 0 && !d->eeg_model) {
3422 qCritical("EEG sphere model not defined.");
3423 goto out;
3424 }
3425 d->sphere_funcs = f = new_dipole_fit_funcs();
3426 if (d->neeg > 0) {
3427 VEC_COPY_3(d->eeg_model->r0,d->r0);
3430 f->eeg_client = d->eeg_model.get();
3431 }
3432 if (d->nmeg > 0) {
3433 /*
3434 * Use the new compensated field computation
3435 * It works the same way independent of whether or not the compensation is in effect
3436 */
3437 comp = FwdCompData::fwd_make_comp_data(comp_data,d->meg_coils.get(),comp_coils,
3440 NULL,
3441 d->r0,NULL);
3442 if (!comp)
3443 goto out;
3446 f->meg_client = comp;
3448 }
3449 printf("Sphere model origin : %6.1f %6.1f %6.1f mm.\n",
3450 1000*d->r0[X_3],1000*d->r0[Y_3],1000*d->r0[Z_3]);
3451 /*
3452 * Finally add the magnetic dipole fitting functions (for special purposes)
3453 */
3454 d->mag_dipole_funcs = f = new_dipole_fit_funcs();
3455 if (d->nmeg > 0) {
3456 /*
3457 * Use the new compensated field computation
3458 * It works the same way independent of whether or not the compensation is in effect
3459 */
3460 comp = FwdCompData::fwd_make_comp_data(comp_data,d->meg_coils.get(),comp_coils,
3463 NULL,
3464 NULL,NULL);
3465 if (!comp)
3466 goto out;
3469 f->meg_client = comp;
3471 }
3474 /*
3475 * Select the appropriate fitting function
3476 */
3477 d->funcs = !d->bemname.isEmpty() ? d->bem_funcs : d->sphere_funcs;
3478
3479 fprintf (stderr,"\n");
3480 return OK;
3481
3482out :
3483 return FAIL;
3484}
3485
3486//=============================================================================================================
3487
3488std::unique_ptr<MNECovMatrix> DipoleFitData::ad_hoc_noise(FwdCoilSet *meg, FwdCoilSet *eeg, float grad_std, float mag_std, float eeg_std)
3489/*
3490 * Specify constant noise values
3491 */
3492{
3493 int nchan;
3494 Eigen::VectorXd stds;
3495 QStringList names, ch_names;
3496 int k,n;
3497
3498 printf("Using standard noise values "
3499 "(MEG grad : %6.1f fT/cm MEG mag : %6.1f fT EEG : %6.1f uV)\n",
3500 1e13*grad_std,1e15*mag_std,1e6*eeg_std);
3501
3502 nchan = 0;
3503 if (meg)
3504 nchan = nchan + meg->ncoil;
3505 if (eeg)
3506 nchan = nchan + eeg->ncoil;
3507
3508 stds.resize(nchan);
3509
3510 n = 0;
3511 if (meg) {
3512 for (k = 0; k < meg->ncoil; k++, n++) {
3513 if (meg->coils[k]->is_axial_coil()) {
3514 stds[n] = mag_std*mag_std;
3515#ifdef TEST_REF
3516 if (meg->coils[k]->type == FIFFV_COIL_CTF_REF_MAG ||
3517 meg->coils[k]->type == FIFFV_COIL_CTF_REF_GRAD ||
3519 stds[n] = 1e6*stds[n];
3520#endif
3521 }
3522 else
3523 stds[n] = grad_std*grad_std;
3524 ch_names.append(meg->coils[k]->chname);
3525 }
3526 }
3527 if (eeg) {
3528 for (k = 0; k < eeg->ncoil; k++, n++) {
3529 stds[n] = eeg_std*eeg_std;
3530 ch_names.append(eeg->coils[k]->chname);
3531 }
3532 }
3533 names = ch_names;
3534 return MNECovMatrix::create(FIFFV_MNE_NOISE_COV,nchan,names,Eigen::VectorXd(),stds);
3535}
3536
3537//=============================================================================================================
3538
3539int DipoleFitData::make_projection(const QList<QString> &projnames,
3540 const QList<FiffChInfo>& chs,
3541 int nch,
3542 MNEProjOp* *res)
3543/*
3544 * Process the projection data
3545 */
3546{
3547 MNEProjOp* all = NULL;
3548 MNEProjOp* one = NULL;
3549 int k,found;
3550 int neeg;
3551
3552 for (k = 0, neeg = 0; k < nch; k++)
3553 if (chs[k].kind == FIFFV_EEG_CH)
3554 neeg++;
3555
3556 if (projnames.size() == 0 && neeg == 0)
3557 return OK;
3558
3559 for (k = 0; k < projnames.size(); k++) {
3560 if ((one = mne_read_proj_op_3(projnames[k])) == NULL)
3561 goto bad;
3562 if (one->nitems == 0) {
3563 printf("No linear projection information in %s.\n",projnames[k].toUtf8().data());
3564 if(one)
3565 delete one;
3566 one = NULL;
3567 }
3568 else {
3569 printf("Loaded projection from %s:\n",projnames[k].toUtf8().data());
3570 { QTextStream errStream(stderr); mne_proj_op_report_3(errStream,"\t",one); }
3571 all = all ? all->combine(one) : (new MNEProjOp())->combine(one);
3572 if(one)
3573 delete one;
3574 one = NULL;
3575 }
3576 }
3577
3578 if (neeg > 0) {
3579 found = FALSE;
3580 if (all) {
3581 for (k = 0; k < all->nitems; k++)
3582 if (all->items[k].kind == FIFFV_MNE_PROJ_ITEM_EEG_AVREF) {
3583 found = TRUE;
3584 break;
3585 }
3586 }
3587 if (!found) {
3588 if ((one = MNEProjOp::create_average_eeg_ref(chs,nch)) != NULL) {
3589 printf("Average EEG reference projection added:\n");
3590 { QTextStream errStream(stderr); mne_proj_op_report_3(errStream,"\t",one); }
3591 all = all ? all->combine(one) : (new MNEProjOp())->combine(one);
3592 if(one)
3593 delete one;
3594 one = NULL;
3595 }
3596 }
3597 }
3598 if (all && all->affect_chs(chs,nch) == 0) {
3599 printf("Projection will not have any effect on selected channels. Projection omitted.\n");
3600 if(all)
3601 delete all;
3602 all = NULL;
3603 }
3604 *res = all;
3605 return OK;
3606
3607bad :
3608 if(all)
3609 delete all;
3610 all = NULL;
3611 return FAIL;
3612}
3613
3614//=============================================================================================================
3615
3617{
3618 float nave_ratio = ((float)f->nave)/(float)nave;
3619 int k;
3620
3621 if (!f->noise)
3622 return OK;
3623
3624 if (f->noise->cov.size() > 0) {
3625 printf("Decomposing the sensor noise covariance matrix...\n");
3626 if (mne_decompose_eigen_cov_3(f->noise.get()) == FAIL)
3627 goto bad;
3628
3629 for (k = 0; k < f->noise->ncov*(f->noise->ncov+1)/2; k++)
3630 f->noise->cov[k] = nave_ratio*f->noise->cov[k];
3631 for (k = 0; k < f->noise->ncov; k++) {
3632 f->noise->lambda[k] = nave_ratio*f->noise->lambda[k];
3633 if (f->noise->lambda[k] < 0.0)
3634 f->noise->lambda[k] = 0.0;
3635 }
3636 if (mne_add_inv_cov_3(f->noise.get()) == FAIL)
3637 goto bad;
3638 }
3639 else {
3640 for (k = 0; k < f->noise->ncov; k++)
3641 f->noise->cov_diag[k] = nave_ratio*f->noise->cov_diag[k];
3642 printf("Decomposition not needed for a diagonal noise covariance matrix.\n");
3643 if (mne_add_inv_cov_3(f->noise.get()) == FAIL)
3644 goto bad;
3645 }
3646 printf("Effective nave is now %d\n",nave);
3647 f->nave = nave;
3648 return OK;
3649
3650bad :
3651 return FAIL;
3652}
3653
3654//=============================================================================================================
3655
3657{
3658 float nave_ratio = ((float)f->nave)/(float)nave;
3659 int k;
3660
3661 if (!f->noise)
3662 return OK;
3663 if (f->fixed_noise)
3664 return OK;
3665
3666 if (f->noise->cov.size() > 0) {
3667 /*
3668 * Do the decomposition and check that the matrix is positive definite
3669 */
3670 printf("Decomposing the noise covariance...");
3671 if (f->noise->cov.size() > 0) {
3672 if (mne_decompose_eigen_cov_3(f->noise.get()) == FAIL)
3673 goto bad;
3674 for (k = 0; k < f->noise->ncov; k++) {
3675 if (f->noise->lambda[k] < 0.0)
3676 f->noise->lambda[k] = 0.0;
3677 }
3678 }
3679 for (k = 0; k < f->noise->ncov*(f->noise->ncov+1)/2; k++)
3680 f->noise->cov[k] = nave_ratio*f->noise->cov[k];
3681 for (k = 0; k < f->noise->ncov; k++) {
3682 f->noise->lambda[k] = nave_ratio*f->noise->lambda[k];
3683 if (f->noise->lambda[k] < 0.0)
3684 f->noise->lambda[k] = 0.0;
3685 }
3686 if (mne_add_inv_cov_3(f->noise.get()) == FAIL)
3687 goto bad;
3688 }
3689 else {
3690 for (k = 0; k < f->noise->ncov; k++)
3691 f->noise->cov_diag[k] = nave_ratio*f->noise->cov_diag[k];
3692 printf("Decomposition not needed for a diagonal noise covariance matrix.\n");
3693 if (mne_add_inv_cov_3(f->noise.get()) == FAIL)
3694 goto bad;
3695 }
3696 printf("Effective nave is now %d\n",nave);
3697 f->nave = nave;
3698 return OK;
3699
3700bad :
3701 return FAIL;
3702}
3703
3704//=============================================================================================================
3705
3707/*
3708 * Do the channel selection and scale with nave
3709 */
3710{
3711 int nave,j,k;
3712 float nonsel_w = 30;
3713 int min_nchan = 20;
3714
3715 if (!f || !f->noise_orig)
3716 return OK;
3717 if (!d)
3718 nave = 1;
3719 else {
3720 if (d->nave < 0)
3721 nave = d->meas->current->nave;
3722 else
3723 nave = d->nave;
3724 }
3725 /*
3726 * Channel selection
3727 */
3728 if (d) {
3729 float *w = MALLOC_3(f->noise_orig->ncov,float);
3730 int nomit_meg,nomit_eeg,nmeg,neeg;
3731
3732 nmeg = neeg = 0;
3733 nomit_meg = nomit_eeg = 0;
3734 for (k = 0; k < f->noise_orig->ncov; k++) {
3735 if (f->noise_orig->ch_class[k] == MNE_COV_CH_EEG)
3736 neeg++;
3737 else
3738 nmeg++;
3739 if (is_selected_in_data(d,f->noise_orig->names[k]))
3740 w[k] = 1.0;
3741 else {
3742 w[k] = nonsel_w;
3743 if (f->noise_orig->ch_class[k] == MNE_COV_CH_EEG)
3744 nomit_eeg++;
3745 else
3746 nomit_meg++;
3747 }
3748 }
3749 f->noise.reset();
3750 if (nmeg > 0 && nmeg-nomit_meg > 0 && nmeg-nomit_meg < min_nchan) {
3751 qCritical("Too few MEG channels remaining");
3752 FREE_3(w);
3753 return FAIL;
3754 }
3755 if (neeg > 0 && neeg-nomit_eeg > 0 && neeg-nomit_eeg < min_nchan) {
3756 qCritical("Too few EEG channels remaining");
3757 FREE_3(w);
3758 return FAIL;
3759 }
3760 f->noise = f->noise_orig->dup();
3761 if (nomit_meg+nomit_eeg > 0) {
3762 if (f->noise->cov.size() > 0) {
3763 for (j = 0; j < f->noise->ncov; j++)
3764 for (k = 0; k <= j; k++) {
3765 f->noise->cov[mne_lt_packed_index_3(j,k)] *= w[j]*w[k];
3766 }
3767 }
3768 else {
3769 for (j = 0; j < f->noise->ncov; j++) {
3770 f->noise->cov_diag[j] *= w[j]*w[j];
3771 }
3772 }
3773 }
3774 FREE_3(w);
3775 }
3776 else {
3777 if (f->noise && f->nave == nave)
3778 return OK;
3779 f->noise = f->noise_orig->dup();
3780 }
3781
3783}
3784
3785//=============================================================================================================
3786
3788 const QString &measname,
3789 const QString& bemname,
3790 Vector3f *r0,
3792 int accurate_coils,
3793 const QString &badname,
3794 const QString &noisename,
3795 float grad_std,
3796 float mag_std,
3797 float eeg_std,
3798 float mag_reg,
3799 float grad_reg,
3800 float eeg_reg,
3801 int diagnoise,
3802 const QList<QString> &projnames,
3803 int include_meg,
3804 int include_eeg)
3805/*
3806 * Background work for modelling
3807 */
3808{
3809 DipoleFitData* res = new DipoleFitData;
3810 int k;
3811 QStringList badlist;
3812 int nbad = 0;
3813 QStringList file_bads;
3814 int file_nbad;
3816 std::unique_ptr<MNECovMatrix> cov;
3817 FwdCoilSet* templates = NULL;
3818 std::unique_ptr<MNECTFCompDataSet> comp_data;
3819 FwdCoilSet* comp_coils = NULL;
3820
3821 /*
3822 * Read the coordinate transformations
3823 */
3824 if (!mriname.isEmpty()) {
3825 res->mri_head_t = std::make_unique<FiffCoordTrans>(FiffCoordTrans::readMriTransform(mriname));
3826 if (res->mri_head_t->isEmpty())
3827 goto bad;
3828 }
3829 else if (!bemname.isEmpty()) {
3830 qWarning("Source of MRI / head transform required for the BEM model is missing");
3831 goto bad;
3832 }
3833 else {
3834 float move[] = { 0.0, 0.0, 0.0 };
3835 float rot[3][3] = { { 1.0, 0.0, 0.0 },
3836 { 0.0, 1.0, 0.0 },
3837 { 0.0, 0.0, 1.0 } };
3838 Eigen::Matrix3f rotMat;
3839 rotMat << rot[0][0], rot[0][1], rot[0][2],
3840 rot[1][0], rot[1][1], rot[1][2],
3841 rot[2][0], rot[2][1], rot[2][2];
3842 Eigen::Vector3f moveVec = Eigen::Map<Eigen::Vector3f>(move);
3843 res->mri_head_t = std::make_unique<FiffCoordTrans>(FIFFV_COORD_MRI,FIFFV_COORD_HEAD,rotMat,moveVec);
3844 }
3845
3846 res->mri_head_t->print();
3847 res->meg_head_t = std::make_unique<FiffCoordTrans>(FiffCoordTrans::readMeasTransform(measname));
3848 if (res->meg_head_t->isEmpty())
3849 goto bad;
3850 res->meg_head_t->print();
3851 /*
3852 * Read the bad channel lists
3853 */
3854 if (!badname.isEmpty()) {
3855 if (mne_read_bad_channels_3(badname,badlist,nbad) != OK)
3856 goto bad;
3857 printf("%d bad channels read from %s.\n",nbad,badname.toUtf8().data());
3858 }
3859 if (mne_read_bad_channel_list_3(measname,file_bads,file_nbad) == OK && file_nbad > 0) {
3860 if (badlist.isEmpty())
3861 nbad = 0;
3862 for (k = 0; k < file_nbad; k++) {
3863 badlist.append(file_bads[k]);
3864 nbad++;
3865 }
3866 file_bads.clear();
3867 printf("%d bad channels read from the data file.\n",file_nbad);
3868 }
3869 printf("%d bad channels total.\n",nbad);
3870 /*
3871 * Read the channel information
3872 */
3873 if (read_meg_eeg_ch_info(measname,
3874 include_meg,
3875 include_eeg,
3876 badlist,
3877 nbad,
3878 res->chs,
3879 &res->nmeg,
3880 &res->neeg) != OK)
3881 goto bad;
3882
3883 if (res->nmeg > 0)
3884 printf("Will use %3d MEG channels from %s\n",res->nmeg,measname.toUtf8().data());
3885 if (res->neeg > 0)
3886 printf("Will use %3d EEG channels from %s\n",res->neeg,measname.toUtf8().data());
3887 {
3888 QString s = mne_channel_names_to_string_3(res->chs,
3889 res->nmeg+res->neeg);
3890 int n;
3892 }
3893 /*
3894 * Make coil definitions
3895 */
3896 res->coord_frame = coord_frame;
3898 //#ifdef USE_SHARE_PATH
3899 // char *coilfile = mne_compose_mne_name("share/mne","coil_def.dat");
3900 //#else
3901 // const char *path = "setup/mne";
3902 // const char *filename = "coil_def.dat";
3903 // const char *coilfile = mne_compose_mne_name(path,filename);
3904
3905 // QString qPath("/usr/pubsw/packages/mne/stable/share/mne/coil_def.dat");
3906
3907 QString qPath = QString(QCoreApplication::applicationDirPath() + "/../resources/general/coilDefinitions/coil_def.dat");
3908 QFile file(qPath);
3909 if ( !QCoreApplication::startingUp() )
3910 qPath = QCoreApplication::applicationDirPath() + QString("/../resources/general/coilDefinitions/coil_def.dat");
3911 else if (!file.exists())
3912 qPath = "../resources/general/coilDefinitions/coil_def.dat";
3913
3914 char *coilfile = MALLOC_3(strlen(qPath.toUtf8().data())+1,char);
3915 strcpy(coilfile,qPath.toUtf8().data());
3916 //#endif
3917
3918 if (!coilfile)
3919 goto bad;
3920 if ((templates = FwdCoilSet::read_coil_defs(coilfile)) == NULL) {
3921 FREE_3(coilfile);
3922 goto bad;
3923 }
3924
3925 Q_ASSERT(res->meg_head_t);
3926 res->meg_coils.reset(templates->create_meg_coils(res->chs,
3927 res->nmeg,
3929 *res->meg_head_t));
3930 if (!res->meg_coils)
3931 goto bad;
3932 res->eeg_els.reset(FwdCoilSet::create_eeg_els(res->chs.mid(res->nmeg),
3933 res->neeg));
3934 if (!res->eeg_els)
3935 goto bad;
3936 printf("Head coordinate coil definitions created.\n");
3937 }
3938 else {
3939 qWarning("Cannot handle computations in %s coordinates",mne_coord_frame_name_3(coord_frame));
3940 goto bad;
3941 }
3942 /*
3943 * Forward model setup
3944 */
3945 res->bemname = bemname;
3946 if (r0) {
3947 res->r0[0] = (*r0)[0];
3948 res->r0[1] = (*r0)[1];
3949 res->r0[2] = (*r0)[2];
3950 }
3951 res->eeg_model.reset(eeg_model);
3952 /*
3953 * Compensation data
3954 */
3955 comp_data = MNECTFCompDataSet::read(measname);
3956 if (!comp_data)
3957 goto bad;
3958 if (comp_data->ncomp > 0) { /* Compensation channel information may be needed */
3959 QList<FiffChInfo> comp_chs;
3960 int ncomp = 0;
3961
3962 printf("%d compensation data sets in %s\n",comp_data->ncomp,measname.toUtf8().data());
3963 QList<FiffChInfo> temp;
3965 temp,
3966 NULL,
3967 comp_chs,
3968 &ncomp,
3969 temp,
3970 NULL,
3971 NULL,
3972 NULL) == FAIL)
3973 goto bad;
3974 if (ncomp > 0) {
3975 if ((comp_coils = templates->create_meg_coils(comp_chs,
3976 ncomp,
3978 *res->meg_head_t)) == NULL) {
3979 goto bad;
3980 }
3981 printf("%d compensation channels in %s\n",comp_coils->ncoil,measname.toUtf8().data());
3982 }
3983 }
3984 else { /* Get rid of the empty data set */
3985 comp_data.reset();
3986 }
3987 /*
3988 * Ready to set up the forward model
3989 */
3990 if (setup_forward_model(res,comp_data.get(),comp_coils) == FAIL)
3991 goto bad;
3993 /*
3994 * Projection data should go here
3995 */
3996 {
3997 MNEProjOp* proj_raw = nullptr;
3998 if (make_projection(projnames,
3999 res->chs,
4000 res->nmeg+res->neeg,
4001 &proj_raw) == FAIL)
4002 goto bad;
4003 res->proj.reset(proj_raw);
4004 }
4005 if (res->proj && res->proj->nitems > 0) {
4006 printf("Final projection operator is:\n");
4007 { QTextStream errStream(stderr); mne_proj_op_report_3(errStream,"\t",res->proj.get()); }
4008
4009 if (mne_proj_op_chs_3(res->proj.get(),res->ch_names,res->nmeg+res->neeg) == FAIL)
4010 goto bad;
4011 if (mne_proj_op_make_proj(res->proj.get()) == FAIL)
4012 goto bad;
4013 }
4014 else
4015 printf("No projection will be applied to the data.\n");
4016
4017 /*
4018 * Noise covariance
4019 */
4020 if (!noisename.isEmpty()) {
4021 if ((cov = mne_read_cov(noisename,FIFFV_MNE_SENSOR_COV)) == NULL)
4022 goto bad;
4023 printf("Read a %s noise-covariance matrix from %s\n",
4024 cov->cov_diag.size() > 0 ? "diagonal" : "full", noisename.toUtf8().data());
4025 }
4026 else {
4027 if ((cov = ad_hoc_noise(res->meg_coils.get(),res->eeg_els.get(),grad_std,mag_std,eeg_std)) == NULL)
4028 goto bad;
4029 }
4030 res->noise = mne_pick_chs_cov_omit(cov.get(),
4031 res->ch_names,
4032 res->nmeg+res->neeg,
4033 TRUE,
4034 res->chs);
4035 if (!res->noise) {
4036 goto bad;
4037 }
4038
4039 printf("Picked appropriate channels from the noise-covariance matrix.\n");
4040 cov.reset();
4041
4042 /*
4043 * Apply the projection operator to the noise-covariance matrix
4044 */
4045 if (res->proj && res->proj->nitems > 0 && res->proj->nvec > 0) {
4046 if (mne_proj_op_apply_cov(res->proj.get(),res->noise.get()) == FAIL)
4047 goto bad;
4048 printf("Projection applied to the covariance matrix.\n");
4049 }
4050
4051 /*
4052 * Force diagonal noise covariance?
4053 */
4054 if (diagnoise) {
4055 mne_revert_to_diag_cov(res->noise.get());
4056 printf("Using only the main diagonal of the noise-covariance matrix.\n");
4057 }
4058
4059 /*
4060 * Regularize the possibly deficient noise-covariance matrix
4061 */
4062 if (res->noise->cov.size() > 0) {
4063 float regs[3];
4064 int do_it;
4065
4066 regs[MNE_COV_CH_MEG_MAG] = mag_reg;
4067 regs[MNE_COV_CH_MEG_GRAD] = grad_reg;
4068 regs[MNE_COV_CH_EEG] = eeg_reg;
4069 /*
4070 * Classify the channels
4071 */
4072 if (mne_classify_channels_cov(res->noise.get(),
4073 res->chs,
4074 res->nmeg+res->neeg) == FAIL)
4075 goto bad;
4076 /*
4077 * Do we need to do anything?
4078 */
4079 for (k = 0, do_it = 0; k < res->noise->ncov; k++) {
4080 if (res->noise->ch_class[k] != MNE_COV_CH_UNKNOWN &&
4081 regs[res->noise->ch_class[k]] > 0.0)
4082 do_it++;
4083 }
4084 /*
4085 * Apply regularization if necessary
4086 */
4087 if (do_it > 0)
4088 mne_regularize_cov(res->noise.get(),regs);
4089 else
4090 printf("No regularization applied to the noise-covariance matrix\n");
4091 }
4092
4093 /*
4094 * Do the decomposition and check that the matrix is positive definite
4095 */
4096 printf("Decomposing the noise covariance...\n");
4097 if (res->noise->cov.size() > 0) {
4098 if (mne_decompose_eigen_cov_3(res->noise.get()) == FAIL)
4099 goto bad;
4100 printf("Eigenvalue decomposition done.\n");
4101 for (k = 0; k < res->noise->ncov; k++) {
4102 if (res->noise->lambda[k] < 0.0)
4103 res->noise->lambda[k] = 0.0;
4104 }
4105 }
4106 else {
4107 printf("Decomposition not needed for a diagonal covariance matrix.\n");
4108 if (mne_add_inv_cov_3(res->noise.get()) == FAIL)
4109 goto bad;
4110 }
4111
4112 badlist.clear();
4113 delete templates;
4114 delete comp_coils;
4115 return res;
4116
4117bad : {
4118 badlist.clear();
4119 delete templates;
4120 delete comp_coils;
4121 if(res)
4122 delete res;
4123 return NULL;
4124 }
4125}
4126
4127//=============================================================================================================
4128
4129//============================= dipole_forward.c =============================
4130
4131void print_fields(float *rd,
4132 float *Q,
4133 float time,
4134 float integ,
4135 DipoleFitData* fit,
4136 MNEMeasData* data)
4137
4138{
4139 float *one = MALLOC_3(data->nchan,float);
4140 int k;
4141 float **fwd = NULL;
4142
4143 if (mne_get_values_from_data_3(time,integ,data->current->data,data->current->np,data->nchan,data->current->tmin,
4144 1.0/data->current->tstep,FALSE,one) == FAIL) {
4145 printf("Cannot pick time: %7.1f ms\n",1000*time);
4146 return;
4147 }
4148 for (k = 0; k < data->nchan; k++)
4149 if (data->chs[k].chpos.coil_type == FIFFV_COIL_CTF_REF_GRAD ||
4150 data->chs[k].chpos.coil_type == FIFFV_COIL_CTF_OFFDIAG_REF_GRAD) {
4151 printf("%g ",1e15*one[k]);
4152 }
4153 printf("\n");
4154
4155 fwd = ALLOC_CMATRIX_3(3,fit->nmeg+fit->neeg);
4157 goto out;
4158
4159 for (k = 0; k < data->nchan; k++)
4160 if (data->chs[k].chpos.coil_type == FIFFV_COIL_CTF_REF_GRAD ||
4161 data->chs[k].chpos.coil_type == FIFFV_COIL_CTF_OFFDIAG_REF_GRAD) {
4162 printf("%g ",1e15*(Q[X_3]*fwd[X_3][k]+Q[Y_3]*fwd[Y_3][k]+Q[Z_3]*fwd[Z_3][k]));
4163 }
4164 printf("\n");
4165
4166out : {
4167 FREE_3(one);
4168 FREE_CMATRIX_3(fwd);
4169 }
4170 return;
4171}
4172
4173//=============================================================================================================
4174
4176 float **rd,
4177 int ndip,
4178 DipoleForward* old)
4179/*
4180 * Compute the forward solution and do other nice stuff
4181 */
4182{
4183 DipoleForward* res;
4184 float **this_fwd;
4185 float S[3];
4186 int k,p;
4187 /*
4188 * Allocate data if necessary
4189 */
4190 if (old && old->ndip == ndip && old->nch == d->nmeg+d->neeg) {
4191 res = old;
4192 }
4193 else {
4194 delete old; old = NULL;
4195 res = new DipoleForward;
4196 res->fwd = ALLOC_CMATRIX_3(3*ndip,d->nmeg+d->neeg);
4197 res->uu = ALLOC_CMATRIX_3(3*ndip,d->nmeg+d->neeg);
4198 res->vv = ALLOC_CMATRIX_3(3*ndip,3);
4199 res->sing = MALLOC_3(3*ndip,float);
4200 res->nch = d->nmeg+d->neeg;
4201 res->rd = ALLOC_CMATRIX_3(ndip,3);
4202 res->scales = MALLOC_3(3*ndip,float);
4203 res->ndip = ndip;
4204 }
4205
4206 for (k = 0; k < ndip; k++) {
4207 VEC_COPY_3(res->rd[k],rd[k]);
4208 this_fwd = res->fwd + 3*k;
4209 /*
4210 * Calculate the field of three orthogonal dipoles
4211 */
4212 if ((DipoleFitData::compute_dipole_field(d,rd[k],TRUE,this_fwd)) == FAIL)
4213 goto bad;
4214 /*
4215 * Choice of column normalization
4216 * (componentwise normalization is not recommended)
4217 */
4219 for (p = 0; p < 3; p++)
4220 S[p] = mne_dot_vectors_3(res->fwd[3*k+p],res->fwd[3*k+p],res->nch);
4221 if (d->column_norm == COLUMN_NORM_COMP) {
4222 for (p = 0; p < 3; p++)
4223 res->scales[3*k+p] = sqrt(S[p]);
4224 }
4225 else {
4226 /*
4227 * Divide by three or not?
4228 */
4229 res->scales[3*k+0] = res->scales[3*k+1] = res->scales[3*k+2] = sqrt(S[0]+S[1]+S[2])/3.0;
4230 }
4231 for (p = 0; p < 3; p++) {
4232 if (res->scales[3*k+p] > 0.0) {
4233 res->scales[3*k+p] = 1.0/res->scales[3*k+p];
4234 mne_scale_vector_3(res->scales[3*k+p],res->fwd[3*k+p],res->nch);
4235 }
4236 else
4237 res->scales[3*k+p] = 1.0;
4238 }
4239 }
4240 else {
4241 res->scales[3*k] = 1.0;
4242 res->scales[3*k+1] = 1.0;
4243 res->scales[3*k+2] = 1.0;
4244 }
4245 }
4246
4247 /*
4248 * SVD
4249 */
4250 if (mne_svd_3(res->fwd,3*ndip,d->nmeg+d->neeg,res->sing,res->vv,res->uu) != 0)
4251 goto bad;
4252
4253 return res;
4254
4255bad : {
4256 if (!old)
4257 delete res;
4258 return NULL;
4259 }
4260}
4261
4262//=============================================================================================================
4263
4265 float *rd,
4266 DipoleForward* old)
4267/*
4268 * Convenience function to compute the field of one dipole
4269 */
4270{
4271 float *rds[1];
4272 rds[0] = rd;
4273 return dipole_forward(d,rds,1,old);
4274}
4275
4276//=============================================================================================================
4277// fit_dipoles.c
4278static float fit_eval(float *rd,int npar,void *user)
4279/*
4280 * Calculate the residual sum of squares
4281 */
4282{
4283 DipoleFitData* fit = (DipoleFitData*)user;
4284 DipoleForward* fwd;
4285 FitDipUserRec* fuser = fit->user;
4286 double Bm2,one;
4287 int ncomp,c;
4288 (void)npar; // avoid unused variable warning.
4289
4290 fwd = fuser->fwd = DipoleFitData::dipole_forward_one(fit,rd,fuser->fwd);
4291 ncomp = fwd->sing[2]/fwd->sing[0] > fuser->limit ? 3 : 2;
4292 if (fuser->report_dim)
4293 printf("ncomp = %d\n",ncomp);
4294
4295 for (c = 0, Bm2 = 0.0; c < ncomp; c++) {
4296 one = mne_dot_vectors_3(fwd->uu[c],fuser->B,fwd->nch);
4297 Bm2 = Bm2 + one*one;
4298 }
4299 return fuser->B2-Bm2;
4300}
4301
4302static int find_best_guess(float *B, /* The whitened data */
4303 int nch,
4304 GuessData* guess, /* Guesses */
4305 float limit, /* Pseudoradial component omission limit */
4306 int *bestp, /* Which is the best */
4307 float *goodp) /* Best goodness of fit */
4308/*
4309 * Thanks to the precomputed SVD everything is really simple
4310 */
4311{
4312 int k,c;
4313 double B2,Bm2,this_good,one;
4314 int best = -1;
4315 float good = 0.0;
4316 DipoleForward* fwd;
4317 int ncomp;
4318
4319 B2 = mne_dot_vectors_3(B,B,nch);
4320 for (k = 0; k < guess->nguess; k++) {
4321 fwd = guess->guess_fwd[k];
4322 if (fwd->nch == nch) {
4323 ncomp = fwd->sing[2]/fwd->sing[0] > limit ? 3 : 2;
4324 for (c = 0, Bm2 = 0.0; c < ncomp; c++) {
4325 one = mne_dot_vectors_3(fwd->uu[c],B,nch);
4326 Bm2 = Bm2 + one*one;
4327 }
4328 this_good = 1.0 - (B2 - Bm2)/B2;
4329 if (this_good > good) {
4330 best = k;
4331 good = this_good;
4332 }
4333 }
4334 }
4335 if (best < 0) {
4336 printf("No reasonable initial guess found.");
4337 return FAIL;
4338 }
4339 *bestp = best;
4340 *goodp = good;
4341 return OK;
4342}
4343
4344static float **make_initial_dipole_simplex(float *r0,
4345 float size)
4346/*
4347 * Make the initial tetrahedron
4348 */
4349{
4350 /*
4351 * For this definition of a regular tetrahedron, see
4352 *
4353 * http://mathworld.wolfram.com/Tetrahedron.html
4354 *
4355 */
4356 float x = sqrt(3.0)/3.0;
4357 float r = sqrt(6.0)/12.0;
4358 float R = 3*r;
4359 float d = x/2.0;
4360 float rr[][3] = { { x , 0.0, -r },
4361 { -d, 0.5, -r },
4362 { -d, -0.5, -r },
4363 { 0.0, 0.0, R } };
4364
4365 float **simplex = ALLOC_CMATRIX_3(4,3);
4366 int j,k;
4367
4368 for (j = 0; j < 4; j++) {
4369 VEC_COPY_3(simplex[j],rr[j]);
4370 for (k = 0; k < 3; k++)
4371 simplex[j][k] = size*simplex[j][k] + r0[k];
4372 }
4373 return simplex;
4374}
4375
4376static int report_func(int loop,
4377 float *fitpar,
4378 int npar,
4379 double fval_lo,
4380 double fval_hi,
4381 double par_diff)
4382/*
4383 * Report periodically
4384 */
4385{
4386 float *r0 = fitpar;
4387 (void) npar; // avoid unused variable warning.
4388 fprintf(stdout,"loop %d rd %7.2f %7.2f %7.2f fval %g %g par diff %g\n",
4389 loop,1000*r0[0],1000*r0[1],1000*r0[2],fval_lo,fval_hi,1000*par_diff);
4390
4391 return OK;
4392}
4393
4394static int fit_Q(DipoleFitData* fit, /* The fit data */
4395 float *B, /* Measurement */
4396 float *rd, /* Dipole position */
4397 float limit, /* Radial component omission limit */
4398 float *Q, /* The result */
4399 int *ncomp,
4400 float *res) /* Residual sum of squares */
4401/*
4402 * fit the dipole moment once the location is known
4403 */
4404{
4405 int c;
4407 float Bm2,one;
4408
4409 if (!fwd)
4410 return FAIL;
4411
4412 *ncomp = fwd->sing[2]/fwd->sing[0] > limit ? 3 : 2;
4413
4414 Q[0] = Q[1] = Q[2] = 0.0;
4415 for (c = 0, Bm2 = 0.0; c < *ncomp; c++) {
4416 one = mne_dot_vectors_3(fwd->uu[c],B,fwd->nch);
4417 mne_add_scaled_vector_to_3(fwd->vv[c],one/fwd->sing[c],Q,3);
4418 Bm2 = Bm2 + one*one;
4419 }
4420 /*
4421 * Counteract the effect of column normalization
4422 */
4423 for (c = 0; c < 3; c++)
4424 Q[c] = fwd->scales[c]*Q[c];
4425 *res = mne_dot_vectors_3(B,B,fwd->nch) - Bm2;
4426
4427 delete fwd;
4428
4429 return OK;
4430}
4431
4432static float rtol(float *vals,int nval)
4433
4434{
4435 float minv,maxv;
4436 int k;
4437
4438 minv = maxv = vals[0];
4439 for (k = 1; k < nval; k++) {
4440 if (vals[k] < minv)
4441 minv = vals[k];
4442 if (vals[k] > maxv)
4443 maxv = vals[k];
4444 }
4445 return 2.0*(maxv-minv)/(maxv+minv);
4446}
4447
4448/*
4449 * This routine comes from Numerical recipes
4450 */
4451
4452#define ALPHA 1.0
4453#define BETA 0.5
4454#define GAMMA 2.0
4455#define MIN_STOL_LOOP 5
4456
4457static float tryf (float **p,
4458 float *y,
4459 float *psum,
4460 int ndim,
4461 float (*func)(float *x,int npar,void *user_data), /* The function to be evaluated */
4462 void *user_data, /* Data to be passed to the above function in each evaluation */
4463 int ihi,
4464 int *neval,
4465 float fac)
4466
4467{
4468 int j;
4469 float fac1,fac2,ytry,*ptry;
4470
4471 ptry = ALLOC_FLOAT_3(ndim);
4472 fac1 = (1.0-fac)/ndim;
4473 fac2 = fac1-fac;
4474 for (j = 0; j < ndim; j++)
4475 ptry[j] = psum[j]*fac1-p[ihi][j]*fac2;
4476 ytry = (*func)(ptry,ndim,user_data);
4477 ++(*neval);
4478 if (ytry < y[ihi]) {
4479 y[ihi] = ytry;
4480 for (j = 0; j < ndim; j++) {
4481 psum[j] += ptry[j]-p[ihi][j];
4482 p[ihi][j] = ptry[j];
4483 }
4484 }
4485 FREE_3(ptry);
4486 return ytry;
4487}
4488
4489int simplex_minimize(float **p, /* The initial simplex */
4490 float *y, /* Function values at the vertices */
4491 int ndim, /* Number of variables */
4492 float ftol, /* Relative convergence tolerance */
4493 float stol,
4494 float (*func)(float *x,int npar,void *user_data),/* The function to be evaluated */
4495 void *user_data, /* Data to be passed to the above function in each evaluation */
4496 int max_eval, /* Maximum number of function evaluations */
4497 int *neval, /* Number of function evaluations */
4498 int report, /* How often to report (-1 = no_reporting) */
4499 int (*report_func)(int loop,
4500 float *fitpar, int npar,
4501 double fval_lo,
4502 double fval_hi,
4503 double par_diff)) /* The function to be called when reporting */
4504/*
4505 * Minimization with the simplex algorithm
4506 * Modified from Numerical recipes
4507 */
4508
4509{
4510 int i,j,ilo,ihi,inhi;
4511 int mpts = ndim+1;
4512 float ytry,ysave,sum,rtol,*psum;
4513 double dsum,diff;
4514 int result = 0;
4515 int count = 0;
4516 int loop = 1;
4517
4518 psum = ALLOC_FLOAT_3(ndim);
4519 *neval = 0;
4520 for (j = 0; j < ndim; j++) {
4521 for (i = 0,sum = 0.0; i<mpts; i++)
4522 sum += p[i][j];
4523 psum[j] = sum;
4524 }
4525 if (report_func != NULL && report > 0)
4526 (void)report_func (0,p[0],ndim,-1.0,-1.0,0.0);
4527
4528 dsum = 0.0;
4529 for (;;count++,loop++) {
4530 ilo = 1;
4531 ihi = y[1]>y[2] ? (inhi = 2,1) : (inhi = 1,2);
4532 for (i = 0; i < mpts; i++) {
4533 if (y[i] < y[ilo]) ilo = i;
4534 if (y[i] > y[ihi]) {
4535 inhi = ihi;
4536 ihi = i;
4537 } else if (y[i] > y[inhi])
4538 if (i != ihi) inhi = i;
4539 }
4540 rtol = 2.0*std::fabs(y[ihi]-y[ilo])/(std::fabs(y[ihi])+std::fabs(y[ilo]));
4541 /*
4542 * Report that we are proceeding...
4543 */
4544 if (count == report && report_func != NULL) {
4545 if (report_func (loop,p[ilo],ndim,y[ilo],y[ihi],sqrt(dsum))) {
4546 printf("Interation interrupted.");
4547 result = -1;
4548 break;
4549 }
4550 count = 0;
4551 }
4552 if (rtol < ftol) break;
4553 if (*neval >= max_eval) {
4554 printf("Maximum number of evaluations exceeded.");
4555 result = -1;
4556 break;
4557 }
4558 if (stol > 0) { /* Has the simplex collapsed? */
4559 for (dsum = 0.0, j = 0; j < ndim; j++) {
4560 diff = p[ilo][j] - p[ihi][j];
4561 dsum += diff*diff;
4562 }
4563 if (loop > MIN_STOL_LOOP && sqrt(dsum) < stol)
4564 break;
4565 }
4566 ytry = tryf(p,y,psum,ndim,func,user_data,ihi,neval,-ALPHA);
4567 if (ytry <= y[ilo])
4568 ytry = tryf(p,y,psum,ndim,func,user_data,ihi,neval,GAMMA);
4569 else if (ytry >= y[inhi]) {
4570 ysave = y[ihi];
4571 ytry = tryf(p,y,psum,ndim,func,user_data,ihi,neval,BETA);
4572 if (ytry >= ysave) {
4573 for (i = 0; i < mpts; i++) {
4574 if (i != ilo) {
4575 for (j = 0; j < ndim; j++) {
4576 psum[j] = 0.5*(p[i][j]+p[ilo][j]);
4577 p[i][j] = psum[j];
4578 }
4579 y[i] = (*func)(psum,ndim,user_data);
4580 }
4581 }
4582 *neval += ndim;
4583 for (j = 0; j < ndim; j++) {
4584 for (i = 0,sum = 0.0; i < mpts; i++)
4585 sum += p[i][j];
4586 psum[j] = sum;
4587 }
4588 }
4589 }
4590 }
4591 FREE_3 (psum);
4592 return (result);
4593}
4594
4595//=============================================================================================================
4596// fit_dipoles.c
4597bool DipoleFitData::fit_one(DipoleFitData* fit, /* Precomputed fitting data */
4598 GuessData* guess, /* The initial guesses */
4599 float time, /* Which time is it? */
4600 float *B, /* The field to fit */
4601 int verbose,
4602 ECD& res /* The fitted dipole */
4603 )
4604{
4605 float **simplex = NULL; /* The simplex */
4606 float vals[4]; /* Values at the vertices */
4607 float limit = 0.2; /* (pseudo) radial component omission limit */
4608 float size = 1e-2; /* Size of the initial simplex */
4609 float ftol[] = { 1e-2, 1e-2 }; /* Tolerances on the the two passes */
4610 float atol[] = { 0.2e-3, 0.2e-3 }; /* If dipole movement between two iterations is less than this,
4611 we consider to have converged */
4612 int ntol = 2;
4613 int max_eval = 1000; /* Limit for fit function evaluations */
4614 int report_interval = verbose ? 1 : -1; /* How often to report the intermediate result */
4615
4616 int best;
4617 float good,rd_guess[3],rd_final[3],Q[3],final_val;
4619 int k,p,neval,neval_tot,nchan,ncomp;
4620 int fit_fail;
4621
4622 nchan = fit->nmeg+fit->neeg;
4623 user.fwd = NULL;
4624
4625 if (fit->proj && fit->proj->project_vector(B,nchan,TRUE) == FAIL)
4626 goto bad;
4627
4628 if (mne_whiten_one_data(B,B,nchan,fit->noise.get()) == FAIL)
4629 goto bad;
4630 /*
4631 * Get the initial guess
4632 */
4633 if (find_best_guess(B,nchan,guess,limit,&best,&good) < 0)
4634 goto bad;
4635
4636 user.limit = limit;
4637 user.B = B;
4638 user.B2 = mne_dot_vectors_3(B,B,nchan);
4639 user.fwd = NULL;
4640 user.report_dim = FALSE;
4641 fit->user = &user;
4642
4643 VEC_COPY_3(rd_guess,guess->rr[best]);
4644 VEC_COPY_3(rd_final,guess->rr[best]);
4645
4646 neval_tot = 0;
4647 fit_fail = FALSE;
4648 for (k = 0; k < ntol; k++) {
4649 /*
4650 * Do first pass with the sphere model
4651 */
4652 if (k == 0)
4653 fit->funcs = fit->sphere_funcs;
4654 else
4655 fit->funcs = !fit->bemname.isEmpty() ? fit->bem_funcs : fit->sphere_funcs;
4656
4657 simplex = make_initial_dipole_simplex(rd_guess,size);
4658 for (p = 0; p < 4; p++)
4659 vals[p] = fit_eval(simplex[p],3,fit);
4660 if (simplex_minimize(simplex, /* The initial simplex */
4661 vals, /* Function values at the vertices */
4662 3, /* Number of variables */
4663 ftol[k], /* Relative convergence tolerance for the target function */
4664 atol[k], /* Absolute tolerance for the change in the parameters */
4665 fit_eval, /* The function to be evaluated */
4666 fit, /* Data to be passed to the above function in each evaluation */
4667 max_eval, /* Maximum number of function evaluations */
4668 &neval, /* Number of function evaluations */
4669 report_interval, /* How often to report (-1 = no_reporting) */
4670 report_func) != OK) {
4671 if (k == 0)
4672 goto bad;
4673 else {
4674 printf("\nWarning (t = %8.1f ms) : g = %6.1f %% final val = %7.3f rtol = %f\n",
4675 1000*time,100*(1 - vals[0]/user.B2),vals[0],rtol(vals,4));
4676 fit_fail = TRUE;
4677 }
4678 }
4679 VEC_COPY_3(rd_final,simplex[0]);
4680 VEC_COPY_3(rd_guess,simplex[0]);
4681 FREE_CMATRIX_3(simplex); simplex = NULL;
4682
4683 neval_tot += neval;
4684 final_val = vals[0];
4685 }
4686 /*
4687 * Confidence limits should be computed here
4688 */
4689 /*
4690 * Compute the dipole moment at the final point
4691 */
4692 if (fit_Q(fit,user.B,rd_final,user.limit,Q,&ncomp,&final_val) == OK) {
4693 res.time = time;
4694 res.valid = true;
4695 for(int i = 0; i < 3; ++i)
4696 res.rd[i] = rd_final[i];
4697 for(int i = 0; i < 3; ++i)
4698 res.Q[i] = Q[i];
4699 res.good = 1.0 - final_val/user.B2;
4700 if (fit_fail)
4701 res.good = -res.good;
4702 res.khi2 = final_val;
4703 if (fit->proj)
4704 res.nfree = nchan-3-ncomp-fit->proj->nvec;
4705 else
4706 res.nfree = nchan-3-ncomp;
4707 res.neval = neval_tot;
4708 }
4709 else
4710 goto bad;
4711 delete user.fwd;
4712 FREE_CMATRIX_3(simplex);
4713
4714 return true;
4715
4716bad : {
4717 delete user.fwd;
4718 FREE_CMATRIX_3(simplex);
4719 return false;
4720 }
4721}
4722
4723//=============================================================================================================
4724
4725int DipoleFitData::compute_dipole_field(DipoleFitData* d, float *rd, int whiten, float **fwd)
4726/*
4727 * Compute the field and take whitening and projection into account
4728 */
4729{
4730 float *eeg_fwd[3];
4731 static float Qx[] = {1.0,0.0,0.0};
4732 static float Qy[] = {0.0,1.0,0.0};
4733 static float Qz[] = {0.0,0.0,1.0};
4734 int k;
4735 /*
4736 * Compute the fields
4737 */
4738 if (d->nmeg > 0) {
4739 if (d->funcs->meg_vec_field) {
4740 if (d->funcs->meg_vec_field(rd,d->meg_coils.get(),fwd,d->funcs->meg_client) != OK)
4741 goto bad;
4742 }
4743 else {
4744 if (d->funcs->meg_field(rd,Qx,d->meg_coils.get(),fwd[0],d->funcs->meg_client) != OK)
4745 goto bad;
4746 if (d->funcs->meg_field(rd,Qy,d->meg_coils.get(),fwd[1],d->funcs->meg_client) != OK)
4747 goto bad;
4748 if (d->funcs->meg_field(rd,Qz,d->meg_coils.get(),fwd[2],d->funcs->meg_client) != OK)
4749 goto bad;
4750 }
4751 }
4752
4753 if (d->neeg > 0) {
4754 if (d->funcs->eeg_vec_pot) {
4755 eeg_fwd[0] = fwd[0]+d->nmeg;
4756 eeg_fwd[1] = fwd[1]+d->nmeg;
4757 eeg_fwd[2] = fwd[2]+d->nmeg;
4758 if (d->funcs->eeg_vec_pot(rd,d->eeg_els.get(),eeg_fwd,d->funcs->eeg_client) != OK)
4759 goto bad;
4760 }
4761 else {
4762 if (d->funcs->eeg_pot(rd,Qx,d->eeg_els.get(),fwd[0]+d->nmeg,d->funcs->eeg_client) != OK)
4763 goto bad;
4764 if (d->funcs->eeg_pot(rd,Qy,d->eeg_els.get(),fwd[1]+d->nmeg,d->funcs->eeg_client) != OK)
4765 goto bad;
4766 if (d->funcs->eeg_pot(rd,Qz,d->eeg_els.get(),fwd[2]+d->nmeg,d->funcs->eeg_client) != OK)
4767 goto bad;
4768 }
4769 }
4770
4771 /*
4772 * Apply projection
4773 */
4774#ifdef DEBUG
4775 fprintf(stdout,"orig : ");
4776 for (k = 0; k < 3; k++)
4777 fprintf(stdout,"%g ",sqrt(mne_dot_vectors_3(fwd[k],fwd[k],d->nmeg+d->neeg)));
4778 fprintf(stdout,"\n");
4779#endif
4780
4781 for (k = 0; k < 3; k++)
4782 if (d->proj && d->proj->project_vector(fwd[k],d->nmeg+d->neeg,TRUE) == FAIL)
4783 goto bad;
4784
4785#ifdef DEBUG
4786 fprintf(stdout,"proj : ");
4787 for (k = 0; k < 3; k++)
4788 fprintf(stdout,"%g ",sqrt(mne_dot_vectors_3(fwd[k],fwd[k],d->nmeg+d->neeg)));
4789 fprintf(stdout,"\n");
4790#endif
4791
4792 /*
4793 * Whiten
4794 */
4795 if (d->noise && whiten) {
4796 if (mne_whiten_data(fwd,fwd,3,d->nmeg+d->neeg,d->noise.get()) == FAIL)
4797 goto bad;
4798 }
4799
4800#ifdef DEBUG
4801 fprintf(stdout,"white : ");
4802 for (k = 0; k < 3; k++)
4803 fprintf(stdout,"%g ",sqrt(mne_dot_vectors_3(fwd[k],fwd[k],d->nmeg+d->neeg)));
4804 fprintf(stdout,"\n");
4805#endif
4806
4807 return OK;
4808
4809bad :
4810 return FAIL;
4811}
#define FIFFV_MNE_SENSOR_COV
#define FIFF_MNE_COV_KIND
#define FIFFV_MNE_COORD_MNI_TAL
#define FIFFV_EEG_CH
#define FIFF_OK
#define FIFFV_MNE_COORD_FS_TAL_LTZ
#define FIFFV_COORD_MRI_SLICE
#define FIFFV_MNE_COORD_CTF_DEVICE
#define FIFF_MNE_COV
#define FIFFV_COORD_DEVICE
#define FIFF_MNE_COV_DIAG
#define FIFFV_COORD_MRI_DISPLAY
#define FIFFV_COIL_CTF_REF_GRAD
#define FIFFV_MNE_COORD_MRI_VOXEL
#define FIFF_MNE_ROW_NAMES
#define FIFFV_MNE_NOISE_COV
#define FIFF_FAIL
#define FIFF_MNE_COV_EIGENVALUES
#define FIFF_MNE_PROJ_ITEM_ACTIVE
#define FIFFV_REF_MEG_CH
#define FIFFV_MNE_COORD_CTF_HEAD
#define FIFFV_MNE_PROJ_ITEM_EEG_AVREF
#define FIFFV_COORD_HPI
#define FIFFV_MEG_CH
#define FIFFV_COIL_CTF_REF_MAG
#define FIFFV_COORD_HEAD
#define FIFFV_COORD_MRI
#define FIFFB_MNE_COV
#define FIFF_MNE_CH_NAME_LIST
#define FIFFV_COORD_ISOTRAK
#define FIFF_MNE_COV_NFREE
#define FIFFB_MNE_PARENT_MEAS_FILE
#define FIFF_MNE_COV_EIGENVECTORS
#define FIFFV_COORD_UNKNOWN
#define FIFFV_MNE_COORD_FS_TAL_GTZ
#define FIFF_UNIT_T
#define FIFFV_MNE_COORD_RAS
#define FIFFB_MNE_BAD_CHANNELS
#define FIFFV_COIL_NONE
#define FIFF_MNE_COV_DIM
FiffStream class declaration.
#define FIFF_PARENT_BLOCK_ID
Definition fiff_file.h:333
#define FIFFB_PROJ
Definition fiff_file.h:409
#define FIFF_NCHAN
Definition fiff_file.h:453
#define FIFFTS_MC_RCS
Definition fiff_file.h:270
#define FIFF_NAME
Definition fiff_file.h:485
#define FIFF_DESCRIPTION
Definition fiff_file.h:486
#define FIFFB_MEAS
Definition fiff_file.h:362
#define FIFFB_PROJ_ITEM
Definition fiff_file.h:410
#define FIFFTS_MC_CCS
Definition fiff_file.h:269
#define FIFF_PROJ_ITEM_VECTORS
Definition fiff_file.h:805
#define FIFFT_DOUBLE
Definition fiff_file.h:233
#define FIFF_COORD_TRANS
Definition fiff_file.h:475
#define FIFF_PROJ_ITEM_KIND
Definition fiff_file.h:800
#define FIFFT_FLOAT
Definition fiff_file.h:232
#define FIFFV_SSS_JOB_NOTHING
Definition fiff_file.h:538
#define FIFFV_BEM_SURF_ID_BRAIN
Definition fiff_file.h:749
#define FIFF_CH_INFO
Definition fiff_file.h:456
#define FIFF_PROJ_ITEM_CH_NAME_LIST
Definition fiff_file.h:809
#define FIFFB_MEAS_INFO
Definition fiff_file.h:363
#define FIFF_PROJ_ITEM_NVEC
Definition fiff_file.h:804
FiffCoordTrans class declaration.
MNECovMatrix class declaration.
#define MNE_COV_CH_MEG_MAG
#define MNE_COV_CH_EEG
#define MNE_COV_CH_MEG_GRAD
#define MNE_COV_CH_UNKNOWN
MNEProjItem class declaration.
MNESurface class declaration.
FwdCompData class declaration.
#define MAXLINE
#define TRUE
#define FALSE
#define OK
#define FAIL
#define FWD_COIL_ACCURACY_ACCURATE
Definition fwd_coil.h:71
#define FWD_COIL_ACCURACY_NORMAL
Definition fwd_coil.h:70
FwdBemModel class declaration.
#define FWD_BEM_UNKNOWN
MNE Meas Data Set (MNEMeasDataSet) class declaration.
MNE Meas Data (MNEMeasData) class declaration.
GuessData class declaration.
#define FREE_3(x)
void mne_string_to_name_list_3(const QString &s, QStringList &listp, int &nlistp)
int read_meg_eeg_ch_info(const QString &name, int do_meg, int do_eeg, const QStringList &bads, int nbad, QList< FiffChInfo > &chsp, int *nmegp, int *neegp)
#define TOO_CLOSE
void mne_free_cmatrix_3(float **m)
#define USE_LIMIT
Eigen::MatrixXf toFloatEigenMatrix_3(float **mat, const int m, const int n)
void mne_free_cov_3(MNECovMatrix *c)
#define MIN_STOL_LOOP
int mne_read_bad_channels_3(const QString &name, QStringList &listp, int &nlistp)
int mne_read_bad_channel_list_3(const QString &name, QStringList &listp, int &nlistp)
#define BETA
void mne_transpose_dsquare(double **mat, int n)
int mne_decompose_eigen_3(double *mat, double *lambda, Eigen::Matrix< float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > &vectors, int dim)
double ** mne_dmatrix_3(int nr, int nc)
int fit_sphere_to_points(const MNESurfaceOrVolume::PointsT &rr, int np, float simplex_size, float *r0, float *R)
float ** mne_cmatrix_3(int nr, int nc)
#define SMALL_VALUE
int is_selected_in_data(mshMegEegData d, const QString &ch_name)
#define FREE_CMATRIX_3(m)
int mne_whiten_one_data(float *data, float *whitened_data, int nchan, MNECovMatrix *C)
MNEProjOp * mne_read_proj_op_3(const QString &name)
DipoleForward * dipole_forward(DipoleFitData *d, float **rd, int ndip, DipoleForward *old)
#define Y_3
#define FIFFV_COIL_CTF_OFFDIAG_REF_GRAD
void mne_proj_op_report_data_3(QTextStream &out, const char *tag, MNEProjOp *op, int list_data, char **exclude, int nexclude)
#define X_3
int mne_svd_3(float **mat, int m, int n, float *sing, float **uu, float **vv)
void fromFloatEigenMatrix_3(const Eigen::MatrixXf &from_mat, float **&to_mat, const int m, const int n)
#define MIN_3(a, b)
#define ALLOC_CMATRIX_3(x, y)
#define FREE_DCMATRIX_3(m)
void mne_transpose_square_3(float **mat, int n)
const char * mne_coord_frame_name_3(int frame)
#define VEC_COPY_3(to, from)
float mne_dot_vectors_3(float *v1, float *v2, int nn)
int mne_get_values_from_data_3(float time, float integ, float **data, int nsamp, int nch, float tmin, float sfreq, int use_abs, float *value)
void mne_free_dcmatrix_3(double **m)
int mne_proj_op_make_proj(MNEProjOp *op)
FiffSparseMatrix * mne_convert_to_sparse_3(float **dense, int nrow, int ncol, int stor_type, float small)
int mne_classify_channels_cov(MNECovMatrix *cov, const QList< FiffChInfo > &chs, int nchan)
#define Z_3
double ** mne_dmatt_dmat_mult2_3(double **m1, double **m2, int d1, int d2, int d3)
#define ALLOC_DCMATRIX_3(x, y)
#define GAMMA
float ** mne_mat_mat_mult_3(float **m1, float **m2, int d1, int d2, int d3)
#define EPS_3
std::unique_ptr< MNECovMatrix > mne_pick_chs_cov_omit(MNECovMatrix *c, const QStringList &new_names, int ncov, int omit_meg_eeg, const QList< FiffChInfo > &chs)
#define ALLOC_FLOAT_3(x)
void mne_proj_op_report_3(QTextStream &out, const char *tag, MNEProjOp *op)
int mne_proj_op_chs_3(MNEProjOp *op, const QStringList &list, int nlist)
#define VEC_DIFF_3(from, to, diff)
int mne_is_diag_cov_3(MNECovMatrix *c)
QString mne_name_list_to_string_3(const QStringList &list)
std::unique_ptr< MNECovMatrix > mne_read_cov(const QString &name, int kind)
MNEProjOp * mne_read_proj_op_from_node_3(FiffStream::SPtr &stream, const FiffDirNode::SPtr &start)
int mne_proj_op_make_proj_bad(MNEProjOp *op, char **bad, int nbad)
int simplex_minimize(float **p, float *y, int ndim, float ftol, float stol, float(*func)(float *x, int npar, void *user_data), void *user_data, int max_eval, int *neval, int report, int(*report_func)(int loop, float *fitpar, int npar, double fval_lo, double fval_hi, double par_diff))
int mne_whiten_data(float **data, float **whitened_data, int np, int nchan, MNECovMatrix *C)
void print_fields(float *rd, float *Q, float time, float integ, DipoleFitData *fit, MNEMeasData *data)
void mne_merge_channels(const QList< FiffChInfo > &chs1, int nch1, const QList< FiffChInfo > &chs2, int nch2, QList< FiffChInfo > &resp, int *nresp)
int mne_decompose_eigen_cov_3(MNECovMatrix *c)
float ** mne_lu_invert_3(float **mat, int dim)
int mne_add_inv_cov_3(MNECovMatrix *c)
void mne_scale_vector_3(double scale, float *v, int nn)
int mne_proj_op_proj_dvector(MNEProjOp *op, double *vec, int nch, int do_complement)
int mne_name_list_match(const QStringList &list1, int nlist1, const QStringList &list2, int nlist2)
#define VEC_LEN_3(x)
int mne_read_bad_channel_list_from_node_3(FiffStream::SPtr &stream, const FiffDirNode::SPtr &pNode, QStringList &listp, int &nlistp)
int mne_proj_op_apply_cov(MNEProjOp *op, MNECovMatrix *c)
void mne_mat_vec_mult2_3(float **m, float *v, float *result, int d1, int d2)
int mne_simplex_minimize(float **p, float *y, int ndim, float ftol, float(*func)(float *x, int npar, void *user_data), void *user_data, int max_eval, int *neval, int report, int(*report_func)(int loop, float *fitpar, int npar, double fval))
void mne_revert_to_diag_cov(MNECovMatrix *c)
#define MALLOC_3(x, t)
int mne_pick_from_named_vector_3(MNENamedVector *vec, const QStringList &names, int nnames, int require_all, float *res)
int mne_read_meg_comp_eeg_ch_info_3(const QString &name, QList< FiffChInfo > &megp, int *nmegp, QList< FiffChInfo > &meg_compp, int *nmeg_compp, QList< FiffChInfo > &eegp, int *neegp, FiffCoordTrans *meg_head_t, fiffId *idp)
QString mne_channel_names_to_string_3(const QList< FiffChInfo > &chs, int nch)
void mne_regularize_cov(MNECovMatrix *c, float *regs)
#define ALPHA
void mne_add_scaled_vector_to_3(float *v1, float scale, float *v2, int nn)
void fromFloatEigenVector_3(const Eigen::VectorXf &from_vec, float *to_vec, const int n)
Electric Current Dipole (ECD) class declaration.
Dipole Fit Data class declaration.
#define COLUMN_NORM_COMP
#define COLUMN_NORM_NONE
#define COLUMN_NORM_LOC
Core MNE data structures (source spaces, source estimates, hemispheres).
struct MNELIB::fitSphereUser fitSphereUserRec
FIFF file I/O and data structures (raw, epochs, evoked, covariance, forward).
qint32 fiff_int_t
Definition fiff_types.h:89
FiffId * fiffId
Backward-compatible pointer typedef for the old fiffId pointer.
Definition fiff_types.h:130
FiffId fiffIdRec
Backward-compatible typedef for the old fiffIdRec struct.
Definition fiff_types.h:126
Inverse source estimation (MNE, dSPM, sLORETA, dipole fitting).
struct INVERSELIB::dipoleFitFuncs dipoleFitFuncsRec
Forward modelling (BEM, MEG/EEG lead fields).
Definition compute_fwd.h:95
const QString name
Channel info descriptor.
Eigen::Vector3f r0
fiff_int_t coil_type
Coordinate transformation description.
QSharedPointer< FiffDirNode > SPtr
FIFF sparse matrix storage.
static FiffSparseMatrix::UPtr fiff_get_float_sparse_matrix(FIFFLIB::FiffTag::SPtr &tag)
FIFF File I/O routines.
static QStringList split_name_list(QString p_sNameList)
QSharedPointer< FiffStream > SPtr
QSharedPointer< FiffTag > SPtr
Definition fiff_tag.h:155
static int fwd_mag_dipole_field_vec(float *rm, FwdCoilSet *coils, float **Bval, void *client)
static FwdBemModel * fwd_bem_load_homog_surface(const QString &name)
static int fwd_sphere_field_vec(float *rd, FwdCoilSet *coils, float **Bval, void *client)
static int fwd_bem_set_head_mri_t(FwdBemModel *m, const FIFFLIB::FiffCoordTrans &t)
static int fwd_bem_field(float *rd, float *Q, FwdCoilSet *coils, float *B, void *client)
static QString fwd_bem_make_bem_sol_name(const QString &name)
static int fwd_bem_load_recompute_solution(const QString &name, int bem_method, int force_recompute, FwdBemModel *m)
static int fwd_bem_specify_coils(FwdBemModel *m, FwdCoilSet *coils)
static int fwd_sphere_field(float *rd, float Q[], FwdCoilSet *coils, float Bval[], void *client)
static int fwd_bem_specify_els(FwdBemModel *m, FwdCoilSet *els)
static FwdBemModel * fwd_bem_load_three_layer_surfaces(const QString &name)
static int fwd_bem_pot_els(float *rd, float *Q, FwdCoilSet *els, float *pot, void *client)
static int fwd_mag_dipole_field(float *rm, float M[], FwdCoilSet *coils, float Bval[], void *client)
QString chname
Definition fwd_coil.h:167
bool is_axial_coil() const
Definition fwd_coil.cpp:268
Collection of FwdCoil objects representing a full MEG or EEG sensor array.
static FwdCoilSet * create_eeg_els(const QList< FIFFLIB::FiffChInfo > &chs, int nch, const FIFFLIB::FiffCoordTrans &t=FIFFLIB::FiffCoordTrans())
static FwdCoilSet * read_coil_defs(const QString &name)
FwdCoilSet * create_meg_coils(const QList< FIFFLIB::FiffChInfo > &chs, int nch, int acc, const FIFFLIB::FiffCoordTrans &t=FIFFLIB::FiffCoordTrans())
This structure is used in the compensated field calculations.
FwdCoilSet * comp_coils
static void fwd_free_comp_data(void *d)
static FwdCompData * fwd_make_comp_data(MNELIB::MNECTFCompDataSet *set, FwdCoilSet *coils, FwdCoilSet *comp_coils, fwdFieldFunc field, fwdVecFieldFunc vec_field, fwdFieldGradFunc field_grad, void *client, fwdUserFreeFunc client_free)
static int fwd_comp_field_vec(float *rd, FwdCoilSet *coils, float **res, void *client)
static int fwd_comp_field(float *rd, float *Q, FwdCoilSet *coils, float *res, void *client)
Multi-layer spherical head model for EEG forward computation.
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)
Measurement data container holding multiple data sets for MNE inverse computations.
QList< FIFFLIB::FiffChInfo > chs
MNEMeasDataSet * current
Combined MEG/EEG measurement data with inverse operator, field mapping, dipole fitting,...
INVERSELIB::MNEMeasData * meas
Workspace for sphere-fitting optimization, holding digitizer point coordinates and count.
const MNESurfaceOrVolume::PointsT * rr
Lookup record mapping a FIFF coordinate frame integer ID to its human-readable name string.
Forward field computation function pointers and client data for MEG and EEG dipole fitting.
MNELIB::mneUserFreeFunc eeg_client_free
MNELIB::mneUserFreeFunc meg_client_free
Workspace for the dipole fitting objective function, holding forward model, measured field,...
Dipole Fit Data implementation.
static int scale_dipole_fit_noise_cov(DipoleFitData *f, int nave)
static int compute_dipole_field(DipoleFitData *d, float *rd, int whiten, float **fwd)
std::unique_ptr< FIFFLIB::FiffCoordTrans > meg_head_t
static DipoleFitData * setup_dipole_fit_data(const QString &mriname, const QString &measname, const QString &bemname, Eigen::Vector3f *r0, FWDLIB::FwdEegSphereModel *eeg_model, int accurate_coils, const QString &badname, const QString &noisename, float grad_std, float mag_std, float eeg_std, float mag_reg, float grad_reg, float eeg_reg, int diagnoise, const QList< QString > &projnames, int include_meg, int include_eeg)
static int select_dipole_fit_noise_cov(DipoleFitData *f, mshMegEegData d)
static std::unique_ptr< MNELIB::MNECovMatrix > ad_hoc_noise(FWDLIB::FwdCoilSet *meg, FWDLIB::FwdCoilSet *eeg, float grad_std, float mag_std, float eeg_std)
std::unique_ptr< MNELIB::MNECovMatrix > noise_orig
std::unique_ptr< FWDLIB::FwdBemModel > bem_model
static int make_projection(const QList< QString > &projnames, const QList< FIFFLIB::FiffChInfo > &chs, int nch, MNELIB::MNEProjOp **res)
std::unique_ptr< MNELIB::MNECovMatrix > noise
static int setup_forward_model(DipoleFitData *d, MNELIB::MNECTFCompDataSet *comp_data, FWDLIB::FwdCoilSet *comp_coils)
static bool fit_one(DipoleFitData *fit, GuessData *guess, float time, float *B, int verbose, ECD &res)
std::unique_ptr< FWDLIB::FwdCoilSet > meg_coils
QList< FIFFLIB::FiffChInfo > chs
static int scale_noise_cov(DipoleFitData *f, int nave)
std::unique_ptr< FWDLIB::FwdEegSphereModel > eeg_model
std::unique_ptr< FIFFLIB::FiffCoordTrans > mri_head_t
static DipoleForward * dipole_forward_one(DipoleFitData *d, float *rd, DipoleForward *old)
std::unique_ptr< FWDLIB::FwdCoilSet > eeg_els
std::unique_ptr< MNELIB::MNEProjOp > proj
Stores forward field matrices and source space data for magnetic dipole fitting.
Single equivalent current dipole with position, orientation, amplitude, and goodness-of-fit.
Definition ecd.h:73
Eigen::Vector3f rd
Definition ecd.h:109
float time
Definition ecd.h:108
float good
Definition ecd.h:111
bool valid
Definition ecd.h:107
float khi2
Definition ecd.h:112
Eigen::Vector3f Q
Definition ecd.h:110
Precomputed guess point grid with forward fields for initial dipole position candidates.
Definition guess_data.h:79
DipoleForward ** guess_fwd
Definition guess_data.h:139
Covariance matrix storage.
Eigen::VectorXd inv_lambda
Eigen::VectorXd lambda
static std::unique_ptr< MNECovMatrix > create_sparse(int kind, int ncov, const QStringList &names, FIFFLIB::FiffSparseMatrix *cov_sparse)
std::unique_ptr< MNEProjOp > proj
static std::unique_ptr< MNECovMatrix > create_diag(int kind, int ncov, const QStringList &names, const Eigen::VectorXd &cov_diag)
static std::unique_ptr< MNECovMatrix > create_dense(int kind, int ncov, const QStringList &names, const Eigen::VectorXd &cov)
std::unique_ptr< MNESssData > sss
Eigen::VectorXd cov
Eigen::VectorXd cov_diag
static std::unique_ptr< MNECovMatrix > create(int kind, int ncov, const QStringList &names, const Eigen::VectorXd &cov, const Eigen::VectorXd &cov_diag)
Eigen::Matrix< float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > eigen
Eigen::VectorXi ch_class
Collection of CTF third-order gradient compensation operators.
static std::unique_ptr< MNECTFCompDataSet > read(const QString &name)
A dense matrix with named rows and columns.
static std::unique_ptr< MNENamedMatrix > build(int nrow, int ncol, const QStringList &rowlist, const QStringList &collist, const Eigen::MatrixXf &data)
Factory: build a named matrix from its constituent parts.
A single SSP (Signal-Space Projection) item.
std::unique_ptr< MNENamedMatrix > vecs
Projection operator managing a set of linear projection items and the final compiled projector matrix...
Definition mne_proj_op.h:83
QStringList names
void free_proj()
Release the compiled projector data.
RowMajorMatrixXf proj_data
static MNEProjOp * create_average_eeg_ref(const QList< FIFFLIB::FiffChInfo > &chs, int nch)
Create an average EEG reference projector.
int affect(const QStringList &list, int nlist)
MNEProjOp * combine(MNEProjOp *from)
Append all projection items from another operator.
int affect_chs(const QList< FIFFLIB::FiffChInfo > &chs, int nch)
QList< MNELIB::MNEProjItem > items
void add_item_active(const MNENamedMatrix *vecs, int kind, const QString &desc, int is_active)
Add a projection item with an explicit active/inactive state.
Container for Signal Space Separation (SSS/Maxwell filtering) expansion coefficients and metadata.
Eigen::VectorXi comp_info
static MNESssData * read_from_node(QSharedPointer< FIFFLIB::FiffStream > &stream, const QSharedPointer< FIFFLIB::FiffDirNode > &start)
This defines a surface.
Definition mne_surface.h:79
Eigen::Matrix< float, Eigen::Dynamic, 3, Eigen::RowMajor > PointsT
static FiffCoordTrans readMriTransform(const QString &name)
static FiffCoordTrans readMeasTransform(const QString &name)
Eigen::MatrixX3f apply_trans(const Eigen::MatrixX3f &rr, bool do_move=true) const
static FiffCoordTrans readFromTag(const QSharedPointer< FiffTag > &tag)