MNE-CPP  0.1.9
A Framework for Electrophysiology
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 
75 void 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 
85 static 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 
102 float **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 
119 float 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 
140 void 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 
156 void 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 
163 void 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 
168 QString 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 
186 QString 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 
205 using namespace Eigen;
206 using namespace FIFFLIB;
207 using namespace MNELIB;
208 
209 //=============================================================================================================
210 // DEFINE MEMBER METHODS
211 //=============================================================================================================
212 
213 MneProjOp::MneProjOp()
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 
252 MneProjOp *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 
274 void 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 
324 void 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 
331 MneProjOp *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 
353 MneProjOp *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 
393 int 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 
410 int 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 
428 int 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 
475 MneProjOp *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;
484  FiffDirNode::SPtr node;
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 
618 out :
619  return op;
620 
621 bad : {
622  if(op)
623  delete op;
624  return NULL;
625  }
626 }
627 
628 //=============================================================================================================
629 
630 MneProjOp *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 
650 void 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 
708 void 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 }
MNELIB::MneProjItem
One linear projection item.
Definition: mne_proj_item.h:77
FIFF_NAME
#define FIFF_NAME
Definition: fiff_file.h:485
MNELIB::MneProjItem::active_file
int active_file
Definition: mne_proj_item.h:105
fiff_tag.h
FiffTag class declaration, which provides fiff tag I/O and processing methods.
FIFFLIB::FiffStream::SPtr
QSharedPointer< FiffStream > SPtr
Definition: fiff_stream.h:107
MNELIB::MneProjItem::desc
QString desc
Definition: mne_proj_item.h:102
FIFFLIB::FiffDirNode::SPtr
QSharedPointer< FiffDirNode > SPtr
Definition: fiff_dir_node.h:76
MNELIB::MneProjItem::vecs
MneNamedMatrix * vecs
Definition: mne_proj_item.h:100
k
int k
Definition: fiff_tag.cpp:322
FIFF_DESCRIPTION
#define FIFF_DESCRIPTION
Definition: fiff_file.h:486
MNELIB::MneProjOp
One linear projection item.
Definition: mne_proj_op.h:83
MNELIB::MneProjItem::has_meg
int has_meg
Definition: mne_proj_item.h:106
MNELIB::MneNamedMatrix::build_named_matrix
static MneNamedMatrix * build_named_matrix(int nrow, int ncol, const QStringList &rowlist, const QStringList &collist, float **data)
Definition: mne_named_matrix.cpp:154
FIFFLIB::FiffStream::split_name_list
static QStringList split_name_list(QString p_sNameList)
Definition: fiff_stream.cpp:1914
fiff_constants.h
Fiff constants.
FIFFLIB::FiffTag::SPtr
QSharedPointer< FiffTag > SPtr
Definition: fiff_tag.h:152
MNELIB::MneProjOp::~MneProjOp
~MneProjOp()
Definition: mne_proj_op.cpp:223
MNELIB::MneProjItem::kind
int kind
Definition: mne_proj_item.h:103
MNELIB::MneNamedMatrix
Matrix specification with a channel list.
Definition: mne_named_matrix.h:84
mne_proj_op.h
MNEProjOp class declaration.
FIFF_NCHAN
#define FIFF_NCHAN
Definition: fiff_file.h:453
FIFFLIB::FiffStream
FIFF File I/O routines.
Definition: fiff_stream.h:104
MNELIB::MneProjItem::nvec
int nvec
Definition: mne_proj_item.h:101
mne_proj_item.h
MNEProjItem class declaration.
MNELIB::MneProjOp::MneProjOp
MneProjOp()
Definition: mne_proj_op.cpp:213
MNELIB::MneProjOp::mne_free_proj_op_proj
static void mne_free_proj_op_proj(MneProjOp *op)
Definition: mne_proj_op.cpp:235
FIFF_MNE_PROJ_ITEM_ACTIVE
#define FIFF_MNE_PROJ_ITEM_ACTIVE
Definition: fiff_constants.h:407
MNELIB::MneProjItem::active
int active
Definition: mne_proj_item.h:104
MNELIB::MneProjItem::has_eeg
int has_eeg
Definition: mne_proj_item.h:107