MNE-CPP 0.1.9
A Framework for Electrophysiology
Loading...
Searching...
No Matches
mne_proj_op.cpp
Go to the documentation of this file.
1//=============================================================================================================
37//=============================================================================================================
38// INCLUDES
39//=============================================================================================================
40
41#include <fiff/fiff_constants.h>
42#include <fiff/fiff_tag.h>
43
44#include "mne_proj_op.h"
45#include "mne_proj_item.h"
46
47#include <QFile>
48
49#include <Eigen/Core>
50
51#ifndef TRUE
52#define TRUE 1
53#endif
54
55#ifndef FALSE
56#define FALSE 0
57#endif
58
59#ifndef FAIL
60#define FAIL -1
61#endif
62
63#ifndef OK
64#define OK 0
65#endif
66
67#define MALLOC_23(x,t) (t *)malloc((x)*sizeof(t))
68
69#define REALLOC_23(x,y,t) (t *)((x == NULL) ? malloc((y)*sizeof(t)) : realloc((x),(y)*sizeof(t)))
70
71#define FREE_23(x) if ((char *)(x) != NULL) free((char *)(x))
72
73#define FREE_CMATRIX_23(m) mne_free_cmatrix_23((m))
74
75void mne_free_cmatrix_23 (float **m)
76{
77 if (m) {
78 FREE_23(*m);
79 FREE_23(m);
80 }
81}
82
83#define ALLOC_CMATRIX_23(x,y) mne_cmatrix_23((x),(y))
84
85static void matrix_error_23(int kind, int nr, int nc)
86
87{
88 if (kind == 1)
89 printf("Failed to allocate memory pointers for a %d x %d matrix\n",nr,nc);
90 else if (kind == 2)
91 printf("Failed to allocate memory for a %d x %d matrix\n",nr,nc);
92 else
93 printf("Allocation error for a %d x %d matrix\n",nr,nc);
94 if (sizeof(void *) == 4) {
95 printf("This is probably because you seem to be using a computer with 32-bit architecture.\n");
96 printf("Please consider moving to a 64-bit platform.");
97 }
98 printf("Cannot continue. Sorry.\n");
99 exit(1);
100}
101
102float **mne_cmatrix_23(int nr,int nc)
103
104{
105 int i;
106 float **m;
107 float *whole;
108
109 m = MALLOC_23(nr,float *);
110 if (!m) matrix_error_23(1,nr,nc);
111 whole = MALLOC_23(nr*nc,float);
112 if (!whole) matrix_error_23(2,nr,nc);
113
114 for(i=0;i<nr;i++)
115 m[i] = whole + i*nc;
116 return m;
117}
118
119float mne_dot_vectors_23 (float *v1,
120 float *v2,
121 int nn)
122
123{
124#ifdef BLAS
125 int one = 1;
126 float res = sdot(&nn,v1,&one,v2,&one);
127 return res;
128#else
129 float res = 0.0;
130 int k;
131
132 for (k = 0; k < nn; k++)
133 res = res + v1[k]*v2[k];
134 return res;
135#endif
136}
137
138//============================= mne_named_matrix.c =============================
139
140void mne_string_to_name_list_23(const QString& s, QStringList& listp,int &nlistp)
141/*
142 * Convert a colon-separated list into a string array
143 */
144{
145 QStringList list;
146
147 if (!s.isEmpty() && s.size() > 0) {
149 //list = s.split(":");
150 }
151 listp = list;
152 nlistp = list.size();
153 return;
154}
155
156void fromFloatEigenMatrix_23(const Eigen::MatrixXf& from_mat, float **& to_mat, const int m, const int n)
157{
158 for ( int i = 0; i < m; ++i)
159 for ( int j = 0; j < n; ++j)
160 to_mat[i][j] = from_mat(i,j);
161}
162
163void fromFloatEigenMatrix_23(const Eigen::MatrixXf& from_mat, float **& to_mat)
164{
165 fromFloatEigenMatrix_23(from_mat, to_mat, from_mat.rows(), from_mat.cols());
166}
167
168QString mne_name_list_to_string_23(const QStringList& list)
169/*
170 * Convert a string array to a colon-separated string
171 */
172{
173 int nlist = list.size();
174 QString res;
175 if (nlist == 0 || list.isEmpty())
176 return res;
177// res[0] = '\0';
178 for (int k = 0; k < nlist-1; k++) {
179 res += list[k];
180 res += ":";
181 }
182 res += list[nlist-1];
183 return res;
184}
185
186QString mne_channel_names_to_string_23(const QList<FIFFLIB::FiffChInfo>& chs, int nch)
187/*
188 * Make a colon-separated string out of channel names
189 */
190{
191 QStringList names;
192 QString res;
193 if (nch <= 0)
194 return res;
195 for (int k = 0; k < nch; k++)
196 names.append(chs.at(k).ch_name);
197 res = mne_name_list_to_string_23(names);
198 return res;
199}
200
201//=============================================================================================================
202// USED NAMESPACES
203//=============================================================================================================
204
205using namespace Eigen;
206using namespace FIFFLIB;
207using namespace MNELIB;
208
209//=============================================================================================================
210// DEFINE MEMBER METHODS
211//=============================================================================================================
212
214: nitems (0)
215, nch (0)
216, nvec (0)
217, proj_data (NULL)
218{
219}
220
221//=============================================================================================================
222
224{
225 // mne_free_proj_op
226 for (int k = 0; k < nitems; k++)
227 if(items[k])
228 delete items[k];
229
230 // mne_free_proj_op_proj
231}
232
233//=============================================================================================================
234
236{
237 if (op == NULL)
238 return;
239
240 FREE_CMATRIX_23(op->proj_data);
241
242 op->names.clear();
243 op->nch = 0;
244 op->nvec = 0;
245 op->proj_data = NULL;
246
247 return;
248}
249
250//=============================================================================================================
251
252MneProjOp *MneProjOp::mne_proj_op_combine(MneProjOp *to, MneProjOp *from)
253/*
254 * Copy items from 'from' operator to 'to' operator
255 */
256{
257 int k;
258 MneProjItem* it;
259
260 if (to == NULL)
261 to = new MneProjOp();
262 if (from) {
263 for (k = 0; k < from->nitems; k++) {
264 it = from->items[k];
265 mne_proj_op_add_item(to,it->vecs,it->kind,it->desc);
266 to->items[to->nitems-1]->active_file = it->active_file;
267 }
268 }
269 return to;
270}
271
272//=============================================================================================================
273
274void MneProjOp::mne_proj_op_add_item_act(MneProjOp *op, MneNamedMatrix *vecs, int kind, const QString& desc, int is_active)
275/*
276 * Add a new item to an existing projection operator
277 */
278{
279 MneProjItem* new_item;
280 int k;
281
282 // op->items = REALLOC(op->items,op->nitems+1,mneProjItem);
283 // op->items[op->nitems] = new_item = new MneProjItem();
284
285 new_item = new MneProjItem();
286 op->items.append(new_item);
287
288 new_item->active = is_active;
289 new_item->vecs = new MneNamedMatrix(*vecs);
290
291 if (kind == FIFFV_MNE_PROJ_ITEM_EEG_AVREF) {
292 new_item->has_meg = FALSE;
293 new_item->has_eeg = TRUE;
294 }
295 else {
296 for (k = 0; k < vecs->ncol; k++) {
297 if (vecs->collist[k].contains("EEG"))//strstr(vecs->collist[k],"EEG") == vecs->collist[k])
298 new_item->has_eeg = TRUE;
299 if (vecs->collist[k].contains("MEG"))//strstr(vecs->collist[k],"MEG") == vecs->collist[k])
300 new_item->has_meg = TRUE;
301 }
302 if (!new_item->has_meg && !new_item->has_eeg) {
303 new_item->has_meg = TRUE;
304 new_item->has_eeg = FALSE;
305 }
306 else if (new_item->has_meg && new_item->has_eeg) {
307 new_item->has_meg = TRUE;
308 new_item->has_eeg = FALSE;
309 }
310 }
311 if (!desc.isEmpty())
312 new_item->desc = desc;
313 new_item->kind = kind;
314 new_item->nvec = new_item->vecs->nrow;
315
316 op->nitems++;
317
318 MneProjOp::mne_free_proj_op_proj(op); /* These data are not valid any more */
319 return;
320}
321
322//=============================================================================================================
323
324void MneProjOp::mne_proj_op_add_item(MneProjOp *op, MneNamedMatrix *vecs, int kind, const QString& desc)
325{
326 mne_proj_op_add_item_act(op, vecs, kind, desc, TRUE);
327}
328
329//=============================================================================================================
330
331MneProjOp *MneProjOp::mne_dup_proj_op(MneProjOp *op)
332/*
333 * Provide a duplicate (item data only)
334 */
335{
336 MneProjOp* dup = new MneProjOp();
337 MneProjItem* it;
338 int k;
339
340 if (!op)
341 return NULL;
342
343 for (k = 0; k < op->nitems; k++) {
344 it = op->items[k];
345 mne_proj_op_add_item_act(dup,it->vecs,it->kind,it->desc,it->active);
346 dup->items[k]->active_file = it->active_file;
347 }
348 return dup;
349}
350
351//=============================================================================================================
352
353MneProjOp *MneProjOp::mne_proj_op_average_eeg_ref(const QList<FiffChInfo>& chs, int nch)
354/*
355 * Make the projection operator for average electrode reference
356 */
357{
358 int eegcount = 0;
359 int k;
360 float **vec_data;
361 QStringList names;
362 MneNamedMatrix* vecs;
363 MneProjOp* op;
364
365 for (k = 0; k < nch; k++)
366 if (chs.at(k).kind == FIFFV_EEG_CH)
367 eegcount++;
368 if (eegcount == 0) {
369 qCritical("No EEG channels specified for average reference.");
370 return NULL;
371 }
372
373 vec_data = ALLOC_CMATRIX_23(1,eegcount);
374
375 for (k = 0; k < nch; k++)
376 if (chs.at(k).kind == FIFFV_EEG_CH)
377 names.append(chs.at(k).ch_name);
378
379 for (k = 0; k < eegcount; k++)
380 vec_data[0][k] = 1.0/sqrt((double)eegcount);
381
382 QStringList emptyList;
383 vecs = MneNamedMatrix::build_named_matrix(1,eegcount,emptyList,names,vec_data);
384
385 op = new MneProjOp();
386 mne_proj_op_add_item(op,vecs,FIFFV_MNE_PROJ_ITEM_EEG_AVREF,"Average EEG reference");
387
388 return op;
389}
390
391//=============================================================================================================
392
393int MneProjOp::mne_proj_op_affect(MneProjOp *op, const QStringList& list, int nlist)
394{
395 int k;
396 int naff;
397
398 if (!op)
399 return 0;
400
401 for (k = 0, naff = 0; k < op->nitems; k++)
402 if (op->items[k]->active && MneProjItem::mne_proj_item_affect(op->items[k],list,nlist))
403 naff += op->items[k]->nvec;
404
405 return naff;
406}
407
408//=============================================================================================================
409
410int MneProjOp::mne_proj_op_affect_chs(MneProjOp *op, const QList<FiffChInfo>& chs, int nch)
411{
412 QString ch_string;
413 int res;
414 QStringList list;
415 int nlist;
416
417 if (nch == 0)
418 return FALSE;
419 ch_string = mne_channel_names_to_string_23(chs,nch);
420 mne_string_to_name_list_23(ch_string,list,nlist);
421 res = mne_proj_op_affect(op,list,nlist);
422 list.clear();
423 return res;
424}
425
426//=============================================================================================================
427
428int MneProjOp::mne_proj_op_proj_vector(MneProjOp *op, float *vec, int nvec, int do_complement)
429/*
430 * Apply projection operator to a vector (floats)
431 * Assume that all dimension checking etc. has been done before
432 */
433{
434 static float *res = NULL;
435 int res_size = 0;
436 float *pvec;
437 float w;
438 int k,p;
439
440 if (!op || op->nitems <= 0 || op->nvec <= 0)
441 return OK;
442
443 if (op->nch != nvec) {
444 printf("Data vector size does not match projection operator");
445 return FAIL;
446 }
447
448 if (op->nch > res_size) {
449 res = REALLOC_23(res,op->nch,float);
450 res_size = op->nch;
451 }
452
453 for (k = 0; k < op->nch; k++)
454 res[k] = 0.0;
455
456 for (p = 0; p < op->nvec; p++) {
457 pvec = op->proj_data[p];
458 w = mne_dot_vectors_23(pvec,vec,op->nch);
459 for (k = 0; k < op->nch; k++)
460 res[k] = res[k] + w*pvec[k];
461 }
462 if (do_complement) {
463 for (k = 0; k < op->nch; k++)
464 vec[k] = vec[k] - res[k];
465 }
466 else {
467 for (k = 0; k < op->nch; k++)
468 vec[k] = res[k];
469 }
470 return OK;
471}
472
473//=============================================================================================================
474
475MneProjOp *MneProjOp::mne_read_proj_op_from_node(FiffStream::SPtr &stream, const FiffDirNode::SPtr &start)
476/*
477 * Load all the linear projection data
478 */
479{
480 MneProjOp* op = NULL;
481 QList<FiffDirNode::SPtr> proj;
482 FiffDirNode::SPtr start_node;
483 QList<FiffDirNode::SPtr> items;
485 int k;
486 QString item_desc,desc_tag;
487 int global_nchan,item_nchan;
488 QStringList item_names;
489 int item_kind;
490 float **item_vectors = NULL;
491 int item_nvec;
492 int item_active;
493 MneNamedMatrix* item;
494 FiffTag::SPtr t_pTag;
495
496 if (!stream) {
497 qCritical("File not open mne_read_proj_op_from_node");
498 goto bad;
499 }
500
501 if (!start || start->isEmpty())
502 start_node = stream->dirtree();
503 else
504 start_node = start;
505
506 op = new MneProjOp();
507 proj = start_node->dir_tree_find(FIFFB_PROJ);
508 if (proj.size() == 0 || proj[0]->isEmpty()) /* The caller must recognize an empty projection */
509 goto out;
510 /*
511 * Only the first projection block is recognized
512 */
513 items = proj[0]->dir_tree_find(FIFFB_PROJ_ITEM);
514 if (items.size() == 0 || items[0]->isEmpty()) /* The caller must recognize an empty projection */
515 goto out;
516 /*
517 * Get a common number of channels
518 */
519 node = proj[0];
520 if(!node->find_tag(stream, FIFF_NCHAN, t_pTag))
521 global_nchan = 0;
522 else {
523 global_nchan = *t_pTag->toInt();
524 // TAG_FREE(tag);
525 }
526 /*
527 * Proceess each item
528 */
529 for (k = 0; k < items.size(); k++) {
530 node = items[k];
531 /*
532 * Complicated procedure for getting the description
533 */
534 item_desc.clear();
535
536 if (node->find_tag(stream, FIFF_NAME, t_pTag)) {
537 item_desc += t_pTag->toString();
538 }
539
540 /*
541 * Take the first line of description if it exists
542 */
543 if (node->find_tag(stream, FIFF_DESCRIPTION, t_pTag)) {
544 desc_tag = t_pTag->toString();
545 int pos;
546 if((pos = desc_tag.indexOf("\n")) >= 0)
547 desc_tag.truncate(pos);
548 if (!item_desc.isEmpty())
549 item_desc += " ";
550 item_desc += desc_tag;
551 }
552 /*
553 * Possibility to override number of channels here
554 */
555 if (!node->find_tag(stream, FIFF_NCHAN, t_pTag)) {
556 item_nchan = global_nchan;
557 }
558 else {
559 item_nchan = *t_pTag->toInt();
560 }
561 if (item_nchan <= 0) {
562 qCritical("Number of channels incorrectly specified for one of the projection items.");
563 goto bad;
564 }
565 /*
566 * Take care of the channel names
567 */
568 if (!node->find_tag(stream, FIFF_PROJ_ITEM_CH_NAME_LIST, t_pTag))
569 goto bad;
570
571 item_names = FiffStream::split_name_list(t_pTag->toString());
572
573 if (item_names.size() != item_nchan) {
574 printf("Channel name list incorrectly specified for proj item # %d",k+1);
575 item_names.clear();
576 goto bad;
577 }
578 /*
579 * Kind of item
580 */
581 if (!node->find_tag(stream, FIFF_PROJ_ITEM_KIND, t_pTag))
582 goto bad;
583 item_kind = *t_pTag->toInt();
584 /*
585 * How many vectors
586 */
587 if (!node->find_tag(stream,FIFF_PROJ_ITEM_NVEC, t_pTag))
588 goto bad;
589 item_nvec = *t_pTag->toInt();
590 /*
591 * The projection data
592 */
593 if (!node->find_tag(stream,FIFF_PROJ_ITEM_VECTORS, t_pTag))
594 goto bad;
595
596 MatrixXf tmp_item_vectors = t_pTag->toFloatMatrix().transpose();
597 item_vectors = ALLOC_CMATRIX_23(tmp_item_vectors.rows(),tmp_item_vectors.cols());
598 fromFloatEigenMatrix_23(tmp_item_vectors, item_vectors);
599
600 /*
601 * Is this item active?
602 */
603 if (node->find_tag(stream, FIFF_MNE_PROJ_ITEM_ACTIVE, t_pTag)) {
604 item_active = *t_pTag->toInt();
605 }
606 else
607 item_active = FALSE;
608 /*
609 * Ready to add
610 */
611 QStringList emptyList;
612 item = MneNamedMatrix::build_named_matrix(item_nvec,item_nchan,emptyList,item_names,item_vectors);
613 mne_proj_op_add_item_act(op,item,item_kind,item_desc,item_active);
614 delete item;
615 op->items[op->nitems-1]->active_file = item_active;
616 }
617
618out :
619 return op;
620
621bad : {
622 if(op)
623 delete op;
624 return NULL;
625 }
626}
627
628//=============================================================================================================
629
630MneProjOp *MneProjOp::mne_read_proj_op(const QString &name)
631{
632 QFile file(name);
633 FiffStream::SPtr stream(new FiffStream(&file));
634
635 if(!stream->open())
636 return NULL;
637
638 MneProjOp* res = NULL;
639
640 FiffDirNode::SPtr t_default;
641 res = mne_read_proj_op_from_node(stream,t_default);
642
643 stream->close();
644
645 return res;
646}
647
648//=============================================================================================================
649
650void MneProjOp::mne_proj_op_report_data(FILE *out, const char *tag, MneProjOp *op, int list_data, char **exclude, int nexclude)
651/*
652 * Output info about the projection operator
653 */
654{
655 int j,k,p,q;
656 MneProjItem* it;
657 MneNamedMatrix* vecs;
658 int found;
659
660 if (out == NULL)
661 return;
662 if (op == NULL)
663 return;
664 if (op->nitems <= 0) {
665 fprintf(out,"Empty operator\n");
666 return;
667 }
668
669 for (k = 0; k < op->nitems; k++) {
670 it = op->items[k];
671 if (list_data && tag)
672 fprintf(out,"%s\n",tag);
673 if (tag)
674 fprintf(out,"%s",tag);
675 fprintf(out,"# %d : %s : %d vecs : %d chs %s %s\n",
676 k+1,it->desc.toUtf8().constData(),it->nvec,it->vecs->ncol,
677 it->has_meg ? "MEG" : "EEG",
678 it->active ? "active" : "idle");
679 if (list_data && tag)
680 fprintf(out,"%s\n",tag);
681 if (list_data) {
682 vecs = op->items[k]->vecs;
683
684 for (q = 0; q < vecs->ncol; q++) {
685 fprintf(out,"%-10s",vecs->collist[q].toUtf8().constData());
686 fprintf(out,q < vecs->ncol-1 ? " " : "\n");
687 }
688 for (p = 0; p < vecs->nrow; p++)
689 for (q = 0; q < vecs->ncol; q++) {
690 for (j = 0, found = 0; j < nexclude; j++) {
691 if (QString::compare(exclude[j],vecs->collist[q]) == 0) {
692 found = 1;
693 break;
694 }
695 }
696 fprintf(out,"%10.5g ",found ? 0.0 : vecs->data[p][q]);
697 fprintf(out,q < vecs->ncol-1 ? " " : "\n");
698 }
699 if (list_data && tag)
700 fprintf(out,"%s\n",tag);
701 }
702 }
703 return;
704}
705
706//=============================================================================================================
707
708void MneProjOp::mne_proj_op_report(FILE *out, const char *tag, MneProjOp *op)
709{
710 mne_proj_op_report_data(out,tag,op, FALSE, NULL, 0);
711}
FiffTag class declaration, which provides fiff tag I/O and processing methods.
Fiff constants.
#define FIFF_MNE_PROJ_ITEM_ACTIVE
int k
Definition fiff_tag.cpp:324
#define FIFF_NCHAN
Definition fiff_file.h:453
#define FIFF_NAME
Definition fiff_file.h:485
#define FIFF_DESCRIPTION
Definition fiff_file.h:486
MNEProjOp class declaration.
MNEProjItem class declaration.
QSharedPointer< FiffDirNode > SPtr
FIFF File I/O routines.
static QStringList split_name_list(QString p_sNameList)
QSharedPointer< FiffStream > SPtr
QSharedPointer< FiffTag > SPtr
Definition fiff_tag.h:152
Matrix specification with a channel list.
static MneNamedMatrix * build_named_matrix(int nrow, int ncol, const QStringList &rowlist, const QStringList &collist, float **data)
One linear projection item.
MneNamedMatrix * vecs
One linear projection item.
Definition mne_proj_op.h:84
static void mne_free_proj_op_proj(MneProjOp *op)