MNE-CPP  0.1.9
A Framework for Electrophysiology
fiff_stream.cpp
Go to the documentation of this file.
1 //=============================================================================================================
38 //=============================================================================================================
39 // INCLUDES
40 //=============================================================================================================
41 
42 #include "fiff_stream.h"
43 #include "fiff_tag.h"
44 #include "fiff_dir_node.h"
45 #include "fiff_ctf_comp.h"
46 #include "fiff_info.h"
47 #include "fiff_info_base.h"
48 #include "fiff_raw_data.h"
49 #include "fiff_cov.h"
50 #include "fiff_coord_trans.h"
51 #include "fiff_ch_info.h"
52 #include "fiff_ch_pos.h"
53 #include "fiff_dig_point.h"
54 #include "fiff_id.h"
55 #include "c/fiff_digitizer_data.h"
56 #include "fiff_dig_point.h"
57 
58 #include <utils/mnemath.h>
59 #include <utils/ioutils.h>
60 
61 #define MALLOC_54(x,t) (t *)malloc((x)*sizeof(t))
62 
63 #ifndef TRUE
64 #define TRUE 1
65 #endif
66 
67 #ifndef FALSE
68 #define FALSE 0
69 #endif
70 
71 #include <iostream>
72 #include <time.h>
73 
74 //=============================================================================================================
75 // EIGEN INCLUDES
76 //=============================================================================================================
77 
78 #include <Eigen/LU>
79 #include <Eigen/Dense>
80 
81 //=============================================================================================================
82 // QT INCLUDES
83 //=============================================================================================================
84 
85 #include <QFile>
86 #include <QTcpSocket>
87 
88 //=============================================================================================================
89 // USED NAMESPACES
90 //=============================================================================================================
91 
92 using namespace FIFFLIB;
93 using namespace UTILSLIB;
94 using namespace Eigen;
95 
96 //=============================================================================================================
97 // DEFINE MEMBER METHODS
98 //=============================================================================================================
99 
100 FiffStream::FiffStream(QIODevice *p_pIODevice)
101 : QDataStream(p_pIODevice)
102 {
103  this->setFloatingPointPrecision(QDataStream::SinglePrecision);
104  this->setByteOrder(QDataStream::BigEndian);
105  this->setVersion(QDataStream::Qt_5_0);
106 }
107 
108 //=============================================================================================================
109 
110 FiffStream::FiffStream(QByteArray * a,
111  QIODevice::OpenMode mode)
112 : QDataStream(a, mode)
113 {
114  this->setFloatingPointPrecision(QDataStream::SinglePrecision);
115  this->setByteOrder(QDataStream::BigEndian);
116  this->setVersion(QDataStream::Qt_5_0);
117 }
118 
119 //=============================================================================================================
120 
122 {
123  QFile* t_pFile = qobject_cast<QFile*>(this->device());
124  QString p_sFileName;
125  if(t_pFile)
126  p_sFileName = t_pFile->fileName();
127  else
128  p_sFileName = QString("TCPSocket");
129 
130  return p_sFileName;
131 }
132 
133 //=============================================================================================================
134 
136 {
137  return m_id;
138 }
139 
140 //=============================================================================================================
141 
142 QList<FiffDirEntry::SPtr>& FiffStream::dir()
143 {
144  return m_dir;
145 }
146 
147 //=============================================================================================================
148 
149 const QList<FiffDirEntry::SPtr>& FiffStream::dir() const
150 {
151  return m_dir;
152 }
153 
154 //=============================================================================================================
155 
156 int FiffStream::nent() const
157 {
158  return m_dir.size();
159 }
160 
161 //=============================================================================================================
162 
164 {
165  return m_dirtree;
166 }
167 
168 //=============================================================================================================
169 
170 fiff_long_t FiffStream::end_block(fiff_int_t kind, fiff_int_t next)
171 {
172  return this->write_int(FIFF_BLOCK_END,&kind,1,next);
173 }
174 
175 //=============================================================================================================
176 
178 {
179  fiff_int_t datasize = 0;
180 
181  *this << (qint32)FIFF_NOP;
182  *this << (qint32)FIFFT_VOID;
183  *this << (qint32)datasize;
184  *this << (qint32)FIFFV_NEXT_NONE;
185 }
186 
187 //=============================================================================================================
188 
190 {
191  this->end_block(FIFFB_RAW_DATA);
192  this->end_block(FIFFB_MEAS);
193  this->end_file();
194  this->close();
195 }
196 
197 //=============================================================================================================
198 
199 bool FiffStream::get_evoked_entries(const QList<FiffDirNode::SPtr> &evoked_node, QStringList &comments, QList<fiff_int_t> &aspect_kinds, QString &t)
200 {
201  comments.clear();
202  aspect_kinds.clear();
203  QList<FiffDirNode::SPtr>::ConstIterator ev;
204 
205  FiffTag::SPtr t_pTag;
206  qint32 kind, pos, k;
207 
208  for(ev = evoked_node.begin(); ev != evoked_node.end(); ++ev)
209  {
210  for(k = 0; k < (*ev)->nent(); ++k)
211  {
212  kind = (*ev)->dir[k]->kind;
213  pos = (*ev)->dir[k]->pos;
214  if (kind == FIFF_COMMENT)
215  {
216  this->read_tag(t_pTag,pos);
217  comments.append(t_pTag->toString());
218  }
219  }
220  FiffDirNode::SPtr my_aspect = (*ev)->dir_tree_find(FIFFB_ASPECT)[0];
221  for(k = 0; k < my_aspect->nent(); ++k)
222  {
223  kind = my_aspect->dir[k]->kind;
224  pos = my_aspect->dir[k]->pos;
225  if (kind == FIFF_ASPECT_KIND)
226  {
227  this->read_tag(t_pTag,pos);
228  aspect_kinds.append(*t_pTag->toInt());
229  }
230  }
231  }
232 
233  if(comments.size() != aspect_kinds.size() || comments.size() == 0)
234  {
235  qWarning("Dataset names in FIF file could not be found.");
236  return false;
237  }
238 
239  t = QString();
240  for(k = 0; k < aspect_kinds.size(); ++k)
241  {
242  t += QString("%1 - \"%2\" (").arg(k).arg(comments[k]);
243  if(aspect_kinds[k] == FIFFV_ASPECT_AVERAGE)
244  t += QString("FIFFV_ASPECT_AVERAGE)\n");
245  else if(aspect_kinds[k] == FIFFV_ASPECT_STD_ERR)
246  t += QString("FIFFV_ASPECT_STD_ERR)\n");
247  else
248  t += QString("unknown)\n");
249  }
250 
251  return true;
252 }
253 
254 //=============================================================================================================
255 
256 bool FiffStream::open(QIODevice::OpenModeFlag mode)
257 {
258  QString t_sFileName = this->streamName();
259  FiffTag::SPtr t_pTag;
260 
261  /*
262  * Try to open...
263  */
264  if (!this->device()->open(mode))
265  {
266  qCritical("Cannot open %s\n", t_sFileName.toUtf8().constData());//consider throw
267  return false;
268  }
269 
270  if(!check_beginning(t_pTag)) // Supposed to get the id already in the beginning - read once approach - for TCP/IP support
271  return false;
272 
273  /*
274  * Read id and directory pointer
275  */
276  if (t_pTag->kind != FIFF_FILE_ID) {
277  qCritical("FIFF file should start with FIFF_FILE_ID!");//consider throw
278  this->device()->close();
279  return false;
280  }
281  m_id = t_pTag->toFiffID();
282 
283  this->read_tag(t_pTag);
284  if (t_pTag->kind != FIFF_DIR_POINTER) {
285  qWarning("Fiff::open: file does have a directory pointer");//consider throw
286  this->device()->close();
287  return false;
288  }
289 
290  //
291  // Read or create the directory tree
292  //
293  qInfo("Creating tag directory for %s...", t_sFileName.toUtf8().constData());
294  m_dir.clear();
295  qint32 dirpos = *t_pTag->toInt();
296  /*
297  * Do we have a directory or not?
298  */
299  if (dirpos <= 0) { /* Must do it in the hard way... */
300  bool ok = false;
301  m_dir = this->make_dir(&ok);
302  if (!ok) {
303  qCritical ("Could not create tag directory!");
304  return false;
305  }
306  }
307  else { /* Just read the directory */
308  if(!this->read_tag(t_pTag, dirpos)) {
309  qCritical("Could not read the tag directory (file probably damaged)!");
310  return false;
311  }
312  m_dir = t_pTag->toDirEntry();
313  }
314 
315  /*
316  * Check for a mistake
317  */
318  if (m_dir[m_dir.size()-2]->kind == FIFF_DIR) {
319  m_dir.removeLast();
320  m_dir[m_dir.size()-1]->kind = -1;
321  m_dir[m_dir.size()-1]->type = -1;
322  m_dir[m_dir.size()-1]->size = -1;
323  m_dir[m_dir.size()-1]->pos = -1;
324  }
325 
326  //
327  // Create the directory tree structure
328  //
329  if((this->m_dirtree = this->make_subtree(m_dir)) == NULL)
330  return false;
331  else
332  this->m_dirtree->parent.clear();
333 
334  //
335  // Back to the beginning
336  //
337  this->device()->seek(SEEK_SET); //fseek(fid,0,'bof');
338  return true;
339 }
340 
341 //=============================================================================================================
342 
344 {
345  if(this->device()->isOpen())
346  this->device()->close();
347 
348  return true;
349 }
350 
351 //=============================================================================================================
352 
353 FiffDirNode::SPtr FiffStream::make_subtree(QList<FiffDirEntry::SPtr> &dentry)
354 {
355  FiffDirNode::SPtr defaultNode;
357  FiffDirNode::SPtr child;
358  FiffTag::SPtr t_pTag;
359  QList<FiffDirEntry::SPtr> dir;
360  qint32 current = 0;
361 
362  node->dir_tree = dentry;
363  node->nent_tree = 1;
364  node->parent = FiffDirNode::SPtr();
365  node->type = FIFFB_ROOT;
366 
367  if (dentry[current]->kind == FIFF_BLOCK_START) {
368  if (!this->read_tag(t_pTag,dentry[current]->pos))
369  return defaultNode;
370  else
371  node->type = *t_pTag->toInt();
372  }
373  else {
374  node->id = this->id();
375  }
376 
377  ++current;
378  int level = 0;
379  for (; current < dentry.size(); ++current) {
380  ++node->nent_tree;
381  if (dentry[current]->kind == FIFF_BLOCK_START) {
382  level++;
383  if (level == 1) {
384  QList<FiffDirEntry::SPtr> sub_dentry = dentry.mid(current);
385  if (!(child = this->make_subtree(sub_dentry)))
386  return defaultNode;
387  child->parent = node;
388  node->children.append(child);
389  }
390  }
391  else if (dentry[current]->kind == FIFF_BLOCK_END) {
392  level--;
393  if (level < 0)
394  break;
395  }
396  else if (dentry[current]->kind == -1)
397  break;
398  else if (level == 0) {
399  /*
400  * Take the node id from the parent block id,
401  * block id, or file id. Let the block id
402  * take precedence over parent block id and file id
403  */
404  if (((dentry[current]->kind == FIFF_PARENT_BLOCK_ID || dentry[current]->kind == FIFF_FILE_ID) && node->id.isEmpty()) || dentry[current]->kind == FIFF_BLOCK_ID) {
405  if (!this->read_tag(t_pTag,dentry[current]->pos))
406  return defaultNode;
407  node->id = t_pTag->toFiffID();
408  }
409  dir.append(FiffDirEntry::SPtr(new FiffDirEntry(*dentry[current])));//Memcopy necessary here - or is a pointer fine?
410  }
411  }
412  /*
413  * Strip unused entries
414  */
415  node->dir = dir;
416  return node;
417 }
418 
419 //=============================================================================================================
420 
422 {
423  QList<FiffDirNode::SPtr> node = p_Node->dir_tree_find(FIFFB_MNE_BAD_CHANNELS);
424  FiffTag::SPtr t_pTag;
425 
426  QStringList bads;
427 
428  if (node.size() > 0)
429  if(node[0]->find_tag(this, FIFF_MNE_CH_NAME_LIST, t_pTag))
430  bads = split_name_list(t_pTag->toString());
431 
432  return bads;
433 }
434 
435 //=============================================================================================================
436 
437 bool FiffStream::read_cov(const FiffDirNode::SPtr& p_Node, fiff_int_t cov_kind, FiffCov& p_covData)
438 {
439  p_covData.clear();
440 
441  //
442  // Find all covariance matrices
443  //
444  QList<FiffDirNode::SPtr> covs = p_Node->dir_tree_find(FIFFB_MNE_COV);
445  if (covs.size() == 0)
446  {
447  qWarning("No covariance matrices found");
448  return false;
449  }
450  //
451  // Is any of the covariance matrices a noise covariance
452  //
453  qint32 p = 0;
454  FiffTag::SPtr tag;
455  bool success = false;
456  fiff_int_t dim, nfree, nn;
457  QStringList names;
458  bool diagmat = false;
459  VectorXd eig;
460  MatrixXd eigvec;
461  VectorXd cov_diag;
462  MatrixXd cov;
463  VectorXd cov_sparse;
464  QStringList bads;
465  for(p = 0; p < covs.size(); ++p)
466  {
467  success = covs[p]->find_tag(this, FIFF_MNE_COV_KIND, tag);
468  if (success && *tag->toInt() == cov_kind)
469  {
470  FiffDirNode::SPtr current = covs[p];
471  //
472  // Find all the necessary data
473  //
474  if (!current->find_tag(this, FIFF_MNE_COV_DIM, tag))
475  {
476  qWarning("Covariance matrix dimension not found.\n");
477  return false;
478  }
479  dim = *tag->toInt();
480  if (!current->find_tag(this, FIFF_MNE_COV_NFREE, tag))
481  nfree = -1;
482  else
483  nfree = *tag->toInt();
484 
485  if (current->find_tag(this, FIFF_MNE_ROW_NAMES, tag))
486  {
487  names = FiffStream::split_name_list(tag->toString());
488  if (names.size() != dim)
489  {
490  qWarning("Number of names does not match covariance matrix dimension\n");
491  return false;
492  }
493  }
494  if (!current->find_tag(this, FIFF_MNE_COV, tag))
495  {
496  if (!current->find_tag(this, FIFF_MNE_COV_DIAG, tag))
497  {
498  qWarning("No covariance matrix data found\n");
499  return false;
500  }
501  else
502  {
503  //
504  // Diagonal is stored
505  //
506  if (tag->type == FIFFT_DOUBLE)
507  {
508  cov_diag = Map<VectorXd>(tag->toDouble(),dim);
509  }
510  else if (tag->type == FIFFT_FLOAT)
511  {
512  cov_diag = Map<VectorXf>(tag->toFloat(),dim).cast<double>();
513  }
514  else {
515  qCritical("Illegal data type for covariance matrix\n");
516  return false;
517  }
518 
519  diagmat = true;
520  qInfo("\t%d x %d diagonal covariance (kind = %d) found.\n", dim, dim, cov_kind);
521  }
522  }
523  else
524  {
525  VectorXd vals;
526  nn = dim*(dim+1)/2;
527  if (tag->type == FIFFT_DOUBLE)
528  {
529  vals = Map<VectorXd>(tag->toDouble(),nn);
530  }
531  else if (tag->type == FIFFT_FLOAT)
532  {
533  vals = Map<VectorXf>(tag->toFloat(),nn).cast<double>();
534  }
535  else
536  {
537  qDebug() << tag->getInfo();
538  return false;
539  }
540 
541  if(!MNEMath::issparse(vals))
542  {
543  //
544  // Lower diagonal is stored
545  //
546  cov = MatrixXd::Zero(dim,dim);
547 
548  // XXX : should remove for loops
549  qint32 q = 0;
550  for(qint32 j = 0; j < dim; ++j)
551  {
552  for(qint32 k = 0; k <= j; ++k)
553  {
554  cov(j,k) = vals(q);
555  ++q;
556  }
557  }
558  for(qint32 j = 0; j < dim; ++j)
559  for(qint32 k = j+1; k < dim; ++k)
560  cov(j,k) = cov(k,j);
561 
562  diagmat = false;
563  qInfo("\t%d x %d full covariance (kind = %d) found.\n", dim, dim, cov_kind);
564 
565  }
566  else
567  {
568  diagmat = false;
569  qDebug() << "ToDo: FiffStream::read_cov - this needs to be debugged.\n";
570  cov = vals;
571  qInfo("\t%d x %d sparse covariance (kind = %d) found.\n", dim, dim, cov_kind);
572  }
573 //MATLAB
574 // if ~issparse(tag.data)
575 // //
576 // // Lower diagonal is stored
577 // //
578 // qDebug() << tag->getInfo();
579 // vals = tag.data;
580 // data = zeros(dim,dim);
581 // % XXX : should remove for loops
582 // q = 1;
583 // for j = 1:dim
584 // for k = 1:j
585 // data(j,k) = vals(q);
586 // q = q + 1;
587 // end
588 // end
589 // for j = 1:dim
590 // for k = j+1:dim
591 // data(j,k) = data(k,j);
592 // end
593 // end
594 // diagmat = false;
595 // fprintf('\t%d x %d full covariance (kind = %d) found.\n',dim,dim,cov_kind);
596 // else
597 // diagmat = false;
598 // data = tag.data;
599 // fprintf('\t%d x %d sparse covariance (kind = %d) found.\n',dim,dim,cov_kind);
600 // end
601 //MATLAB END
602  }
603  //
604  // Read the possibly precomputed decomposition
605  //
606  FiffTag::SPtr tag1;
607  FiffTag::SPtr tag2;
608  if (current->find_tag(this, FIFF_MNE_COV_EIGENVALUES, tag1) && current->find_tag(this, FIFF_MNE_COV_EIGENVECTORS, tag2))
609  {
610  eig = VectorXd(Map<VectorXd>(tag1->toDouble(),dim));
611  eigvec = tag2->toFloatMatrix().cast<double>();
612  eigvec.transposeInPlace();
613  }
614  //
615  // Read the projection operator
616  //
617  QList<FiffProj> projs = this->read_proj(current);
618  //
619  // Read the bad channel list
620  //
621  bads = this->read_bad_channels(current);
622  //
623  // Put it together
624  //
625  p_covData.clear();
626 
627  p_covData.kind = cov_kind;
628  p_covData.diag = diagmat;
629  p_covData.dim = dim;
630  p_covData.names = names;
631 
632  if(cov_diag.size() > 0)
633  p_covData.data = cov_diag;
634  else if(cov.size() > 0)
635  p_covData.data = cov;
636  else if(cov_sparse.size() > 0)
637  p_covData.data = cov_sparse;
638 
639  p_covData.projs = projs;
640  p_covData.bads = bads;
641  p_covData.nfree = nfree;
642  p_covData.eig = eig;
643  p_covData.eigvec = eigvec;
644 
645  //
646  return true;
647  }
648  }
649 
650  qInfo("Did not find the desired covariance matrix\n");
651  return false;
652 }
653 
654 //=============================================================================================================
655 
656 QList<FiffCtfComp> FiffStream::read_ctf_comp(const FiffDirNode::SPtr& p_Node, const QList<FiffChInfo>& p_Chs)
657 {
658  QList<FiffCtfComp> compdata;
659  QList<FiffDirNode::SPtr> t_qListComps = p_Node->dir_tree_find(FIFFB_MNE_CTF_COMP_DATA);
660 
661  qint32 i, k, p, col, row;
662  fiff_int_t kind, pos;
663  FiffTag::SPtr t_pTag;
664  for (k = 0; k < t_qListComps.size(); ++k)
665  {
666  FiffDirNode::SPtr node = t_qListComps[k];
667  //
668  // Read the data we need
669  //
671  this->read_named_matrix(node, FIFF_MNE_CTF_COMP_DATA, *mat.data());
672  for(p = 0; p < node->nent(); ++p)
673  {
674  kind = node->dir[p]->kind;
675  pos = node->dir[p]->pos;
676  if (kind == FIFF_MNE_CTF_COMP_KIND)
677  {
678  this->read_tag(t_pTag, pos);
679  break;
680  }
681  }
682  if (!t_pTag)
683  {
684  qWarning("Compensation type not found\n");
685  return compdata;
686  }
687  //
688  // Get the compensation kind and map it to a simple number
689  //
690  FiffCtfComp one;
691  one.ctfkind = *t_pTag->toInt();
692 
693  t_pTag.clear();
694 
695  one.kind = -1;
696  if (one.ctfkind == 1194410578) //hex2dec('47314252')
697  one.kind = 1;
698  else if (one.ctfkind == 1194476114) //hex2dec('47324252')
699  one.kind = 2;
700  else if (one.ctfkind == 1194541650) //hex2dec('47334252')
701  one.kind = 3;
702  else if (one.ctfkind == 1194479433)
703  one.kind = 4;
704  else if (one.ctfkind == 1194544969)
705  one.kind = 5;
706  else
707  one.kind = one.ctfkind;
708 
709  for (p = 0; p < node->nent(); ++p)
710  {
711  kind = node->dir[p]->kind;
712  pos = node->dir[p]->pos;
713  if (kind == FIFF_MNE_CTF_COMP_CALIBRATED)
714  {
715  this->read_tag(t_pTag, pos);
716  break;
717  }
718  }
719  bool calibrated;
720  if (!t_pTag)
721  calibrated = false;
722  else
723  calibrated = (bool)*t_pTag->toInt();
724 
725  one.save_calibrated = calibrated;
726  one.rowcals = MatrixXd::Ones(1,mat->data.rows());//ones(1,size(mat.data,1));
727  one.colcals = MatrixXd::Ones(1,mat->data.cols());//ones(1,size(mat.data,2));
728  if (!calibrated)
729  {
730  //
731  // Calibrate...
732  //
733  //
734  // Do the columns first
735  //
736  QStringList ch_names;
737  for (p = 0; p < p_Chs.size(); ++p)
738  ch_names.append(p_Chs[p].ch_name);
739 
740  qint32 count;
741  MatrixXd col_cals(mat->data.cols(), 1);
742  col_cals.setZero();
743  for (col = 0; col < mat->data.cols(); ++col)
744  {
745  count = 0;
746  for (i = 0; i < ch_names.size(); ++i)
747  {
748  if (QString::compare(mat->col_names.at(col),ch_names.at(i)) == 0)
749  {
750  count += 1;
751  p = i;
752  }
753  }
754  if (count == 0)
755  {
756  qWarning("Channel %s is not available in data",mat->col_names.at(col).toUtf8().constData());
757  return compdata;
758  }
759  else if (count > 1)
760  {
761  qWarning("Ambiguous channel %s",mat->col_names.at(col).toUtf8().constData());
762  return compdata;
763  }
764  col_cals(col,0) = 1.0f/(p_Chs[p].range*p_Chs[p].cal);
765  }
766  //
767  // Then the rows
768  //
769  MatrixXd row_cals(mat->data.rows(), 1);
770  row_cals.setZero();
771  for (row = 0; row < mat->data.rows(); ++row)
772  {
773  count = 0;
774  for (i = 0; i < ch_names.size(); ++i)
775  {
776  if (QString::compare(mat->row_names.at(row),ch_names.at(i)) == 0)
777  {
778  count += 1;
779  p = i;
780  }
781  }
782 
783  if (count == 0)
784  {
785  qWarning("Channel %s is not available in data",mat->row_names.at(row).toUtf8().constData());
786  return compdata;
787  }
788  else if (count > 1)
789  {
790  qWarning("Ambiguous channel %s",mat->row_names.at(row).toUtf8().constData());
791  return compdata;
792  }
793 
794  row_cals(row, 0) = p_Chs[p].range*p_Chs[p].cal;
795  }
796  mat->data = row_cals.asDiagonal()* mat->data *col_cals.asDiagonal();
797  one.rowcals = row_cals;
798  one.colcals = col_cals;
799  }
800  one.data = mat;
801  compdata.append(one);
802  }
803 
804  if (compdata.size() > 0)
805  qInfo("\tRead %d compensation matrices\n",compdata.size());
806 
807  return compdata;
808 }
809 
810 //=============================================================================================================
811 
813 {
814  p_digData.coord_frame = FIFFV_COORD_UNKNOWN;
815  fiff_int_t kind = -1;
816  fiff_int_t pos = -1;
817  int npoint = 0;
818  FiffTag::SPtr t_pTag;
819 
820  QList<FiffDirNode::SPtr> t_qListDigData = p_Node->dir_tree_find(FIFFB_ISOTRAK);
821 
822  //Check if digitizer data is available
823  if(t_qListDigData.isEmpty()) {
824  t_qListDigData = p_Node->dir_tree_find(FIFFB_MRI_SET);
825 
826  if(t_qListDigData.isEmpty()) {
827  printf( "No Isotrak data found in %s", this->streamName().toLatin1().data());
828  return false;
829  } else {
830  p_digData.coord_frame = FIFFV_COORD_MRI;
831  }
832  } else {
833  p_digData.coord_frame = FIFFV_COORD_HEAD;
834  }
835 
836  // Read actual data and store it
837  for (int k = 0; k < t_qListDigData.first()->nent(); ++k) {
838  kind = t_qListDigData.first()->dir[k]->kind;
839  pos = t_qListDigData.first()->dir[k]->pos;
840 
841  switch(kind) {
842  case FIFF_DIG_POINT:
843  this->read_tag(t_pTag, pos);
844  p_digData.points.append(t_pTag->toDigPoint());
845  break;
847  this->read_tag(t_pTag, pos);
848  p_digData.coord_frame = *t_pTag->toInt();
849  break;
850  }
851  }
852 
853  npoint = p_digData.points.size();
854 
855  if (npoint == 0) {
856  printf( "No digitizer data in %s", this->streamName().toLatin1().data());
857  return false;
858  }
859 
860  for (auto& dig : p_digData.points){
861  dig.coord_frame = p_digData.coord_frame;
862  }
863 
864  //Add other information as default
865  p_digData.filename = this->streamName();
866  p_digData.npoint = npoint;
867 
868  for (int k = 0; k < p_digData.npoint; k++) {
869  p_digData.active.append(TRUE);
870  p_digData.discard.append(FALSE);
871  }
872 
873  return true;
874 }
875 
876 //=============================================================================================================
877 
879 {
880  p_InfoForward.clear();
881 
882  //
883  // Find the desired blocks
884  //
885  QList<FiffDirNode::SPtr> parent_meg = p_Node->dir_tree_find(FIFFB_MNE_PARENT_MEAS_FILE);
886 
887  if (parent_meg.size() == 0)
888  {
889  qWarning("No parent MEG information found in operator\n");
890  return false;
891  }
892 
893  FiffTag::SPtr t_pTag;
894 
895  QList<FiffChInfo> chs;
896  FiffCoordTrans cand;
897  fiff_int_t kind = -1;
898  fiff_int_t pos = -1;
899 
900  for (qint32 k = 0; k < parent_meg[0]->nent(); ++k)
901  {
902  kind = parent_meg[0]->dir[k]->kind;
903  pos = parent_meg[0]->dir[k]->pos;
904  if (kind == FIFF_CH_INFO)
905  {
906  this->read_tag(t_pTag, pos);
907  chs.append( t_pTag->toChInfo() );
908  }
909  }
910 
911  //
912  // Add the channel information and make a list of channel names
913  // for convenience
914  //
915  p_InfoForward.chs = chs;
916  for (qint32 c = 0; c < p_InfoForward.chs.size(); ++c)
917  p_InfoForward.ch_names << p_InfoForward.chs[c].ch_name;
918 
919  p_InfoForward.nchan = chs.size();
920 
921  //
922  // Get the MEG device <-> head coordinate transformation
923  //
924  if(parent_meg[0]->find_tag(this, FIFF_COORD_TRANS, t_pTag))
925  {
926  cand = t_pTag->toCoordTrans();
927  if(cand.from == FIFFV_COORD_DEVICE && cand.to == FIFFV_COORD_HEAD)
928  p_InfoForward.dev_head_t = cand;
929  else if (cand.from == FIFFV_MNE_COORD_CTF_HEAD && cand.to == FIFFV_COORD_HEAD)
930  p_InfoForward.ctf_head_t = cand;
931  else
932  qWarning("MEG device/head coordinate transformation not found");
933  }
934  else
935  qWarning("MEG/head coordinate transformation not found.\n");
936 
937  //
938  // Load the bad channel list
939  //
940  p_InfoForward.bads = this->read_bad_channels(p_Node);
941 
942  return true;
943 }
944 
945 //=============================================================================================================
946 
948 {
949 // if (info)
950 // delete info;
951  info.clear();
952  //
953  // Find the desired blocks
954  //
955  QList<FiffDirNode::SPtr> meas = p_Node->dir_tree_find(FIFFB_MEAS);
956 
957  if (meas.size() == 0)
958  {
959  qWarning("Could not find measurement data\n");
960  return false;
961  }
962  //
963  QList<FiffDirNode::SPtr> meas_info = meas[0]->dir_tree_find(FIFFB_MEAS_INFO);
964  if (meas_info.count() == 0) {
965  qWarning("Could not find measurement info\n");
966 // delete meas[0];
967  return false;
968  }
969  //
970  // Read measurement info
971  //
972  FiffTag::SPtr t_pTag;
973 
974  fiff_int_t nchan = -1;
975  float sfreq = -1.0f;
976  float linefreq = -1.0f;
977  QList<FiffChInfo> chs;
978  float lowpass = -1.0f;
979  float highpass = -1.0f;
980 
981  int proj_id = 0;
982  QString proj_name = "";
983  QString xplotter_layout = "";
984 
985  QString utc_offset = "";
986  fiff_int_t gantry_angle = -1;
987 
988  QString experimenter = "";
989  QString description = "";
990 
991  FiffChInfo t_chInfo;
992 
993  FiffCoordTrans cand;// = NULL;
994  FiffCoordTrans dev_head_t;// = NULL;
995  FiffCoordTrans ctf_head_t;// = NULL;
996 
997  fiff_int_t meas_date[2];
998  meas_date[0] = -1;
999  meas_date[1] = -1;
1000 
1001  fiff_int_t kind = -1;
1002  fiff_int_t pos = -1;
1003 
1004  for (qint32 k = 0; k < meas_info[0]->nent(); ++k)
1005  {
1006  kind = meas_info[0]->dir[k]->kind;
1007  pos = meas_info[0]->dir[k]->pos;
1008  switch (kind)
1009  {
1010  case FIFF_NCHAN:
1011  this->read_tag(t_pTag, pos);
1012  nchan = *t_pTag->toInt();
1013  break;
1014  case FIFF_SFREQ:
1015  this->read_tag(t_pTag, pos);
1016  sfreq = *t_pTag->toFloat();
1017  break;
1018  case FIFF_LINE_FREQ:
1019  this->read_tag(t_pTag, pos);
1020  linefreq = *t_pTag->toFloat();
1021  break;
1022  case FIFF_CH_INFO:
1023  this->read_tag(t_pTag, pos);
1024  chs.append( t_pTag->toChInfo() );
1025  break;
1026  case FIFF_LOWPASS:
1027  this->read_tag(t_pTag, pos);
1028  lowpass = *t_pTag->toFloat();
1029  break;
1030  case FIFF_HIGHPASS:
1031  this->read_tag(t_pTag, pos);
1032  highpass = *t_pTag->toFloat();
1033  break;
1034  case FIFF_MEAS_DATE:
1035  this->read_tag(t_pTag, pos);
1036  meas_date[0] = t_pTag->toInt()[0];
1037  meas_date[1] = t_pTag->toInt()[1];
1038  break;
1039  case FIFF_COORD_TRANS:
1040  //ToDo: This has to be debugged!!
1041  this->read_tag(t_pTag, pos);
1042  cand = t_pTag->toCoordTrans();
1043  if(cand.from == FIFFV_COORD_DEVICE && cand.to == FIFFV_COORD_HEAD)
1044  dev_head_t = cand;
1045  else if (cand.from == FIFFV_MNE_COORD_CTF_HEAD && cand.to == FIFFV_COORD_HEAD)
1046  ctf_head_t = cand;
1047  break;
1048  case FIFF_PROJ_ID:
1049  this->read_tag(t_pTag,pos);
1050  proj_id = *t_pTag->toInt();
1051  break;
1052  case FIFF_PROJ_NAME:
1053  this->read_tag(t_pTag,pos);
1054  proj_name = t_pTag->toString();
1055  break;
1056  case FIFF_XPLOTTER_LAYOUT:
1057  this->read_tag(t_pTag,pos);
1058  xplotter_layout = t_pTag->toString();
1059  break;
1060  case FIFF_EXPERIMENTER:
1061  this->read_tag(t_pTag,pos);
1062  experimenter = t_pTag->toString();
1063  break;
1064  case FIFF_DESCRIPTION:
1065  this->read_tag(t_pTag,pos);
1066  description = t_pTag->toString();
1067  break;
1068  case FIFF_GANTRY_ANGLE:
1069  this->read_tag(t_pTag,pos);
1070  gantry_angle = *t_pTag->toInt();
1071  break;
1072  case FIFF_UTC_OFFSET:
1073  this->read_tag(t_pTag,pos);
1074  utc_offset = t_pTag->toString();
1075  break;
1076  }
1077  }
1078  //
1079  // Check that we have everything we need
1080  //
1081  if (nchan < 0)
1082  {
1083  qWarning("Number of channels in not defined\n");
1084  return false;
1085  }
1086  if (sfreq < 0)
1087  {
1088  qWarning("Sampling frequency is not defined\n");
1089  return false;
1090  }
1091  if (linefreq < 0)
1092  {
1093  qWarning("Line frequency is not defined\n");
1094  }
1095  if (chs.size() == 0)
1096  {
1097  qWarning("Channel information not defined\n");
1098  return false;
1099  }
1100  if (chs.size() != nchan)
1101  {
1102  qWarning("Incorrect number of channel definitions found\n");
1103  return false;
1104  }
1105 
1106  if (dev_head_t.isEmpty() || ctf_head_t.isEmpty())
1107  {
1108  QList<FiffDirNode::SPtr> hpi_result = meas_info[0]->dir_tree_find(FIFFB_HPI_RESULT);
1109  if (hpi_result.size() == 1)
1110  {
1111  for( qint32 k = 0; k < hpi_result[0]->nent(); ++k)
1112  {
1113  kind = hpi_result[0]->dir[k]->kind;
1114  pos = hpi_result[0]->dir[k]->pos;
1115  if (kind == FIFF_COORD_TRANS)
1116  {
1117  this->read_tag(t_pTag, pos);
1118  cand = t_pTag->toCoordTrans();
1119  if (cand.from == FIFFV_COORD_DEVICE && cand.to == FIFFV_COORD_HEAD)
1120  dev_head_t = cand;
1121  else if (cand.from == FIFFV_MNE_COORD_CTF_HEAD && cand.to == FIFFV_COORD_HEAD)
1122  ctf_head_t = cand;
1123  }
1124  }
1125  }
1126  }
1127  //
1128  // Locate the Polhemus data
1129  //
1130  QList<FiffDirNode::SPtr> isotrak = meas_info[0]->dir_tree_find(FIFFB_ISOTRAK);
1131 
1132  QList<FiffDigPoint> dig;
1133  fiff_int_t coord_frame = FIFFV_COORD_HEAD;
1134  FiffCoordTrans dig_trans;
1135  qint32 k = 0;
1136 
1137  if (isotrak.size() == 1)
1138  {
1139  for (k = 0; k < isotrak[0]->nent(); ++k)
1140  {
1141  kind = isotrak[0]->dir[k]->kind;
1142  pos = isotrak[0]->dir[k]->pos;
1143  if (kind == FIFF_DIG_POINT)
1144  {
1145  this->read_tag(t_pTag, pos);
1146  dig.append(t_pTag->toDigPoint());
1147  }
1148  else
1149  {
1150  if (kind == FIFF_MNE_COORD_FRAME)
1151  {
1152  this->read_tag(t_pTag, pos);
1153  qDebug() << "NEEDS To BE DEBBUGED: FIFF_MNE_COORD_FRAME" << t_pTag->getType();
1154  coord_frame = *t_pTag->toInt();
1155  }
1156  else if (kind == FIFF_COORD_TRANS)
1157  {
1158  this->read_tag(t_pTag, pos);
1159  qDebug() << "NEEDS To BE DEBBUGED: FIFF_COORD_TRANS" << t_pTag->getType();
1160  dig_trans = t_pTag->toCoordTrans();
1161  }
1162  }
1163  }
1164  }
1165  for(k = 0; k < dig.size(); ++k)
1166  dig[k].coord_frame = coord_frame;
1167 
1168  if (!dig_trans.isEmpty()) //if exist('dig_trans','var')
1169  if (dig_trans.from != coord_frame && dig_trans.to != coord_frame)
1170  dig_trans.clear();
1171 
1172  //
1173  // Locate the acquisition information
1174  //
1175  QList<FiffDirNode::SPtr> acqpars = meas_info[0]->dir_tree_find(FIFFB_DACQ_PARS);
1176  QString acq_pars;
1177  QString acq_stim;
1178  if (acqpars.size() == 1)
1179  {
1180  for( k = 0; k < acqpars[0]->nent(); ++k)
1181  {
1182  kind = acqpars[0]->dir[k]->kind;
1183  pos = acqpars[0]->dir[k]->pos;
1184  if (kind == FIFF_DACQ_PARS)
1185  {
1186  this->read_tag(t_pTag, pos);
1187  acq_pars = t_pTag->toString();
1188  }
1189  else if (kind == FIFF_DACQ_STIM)
1190  {
1191  this->read_tag(t_pTag, pos);
1192  acq_stim = t_pTag->toString();
1193  }
1194  }
1195  }
1196  //
1197  // Load the SSP data
1198  //
1199  QList<FiffProj> projs = this->read_proj(meas_info[0]);//ToDo Member Function
1200  //
1201  // Load the CTF compensation data
1202  //
1203  QList<FiffCtfComp> comps = this->read_ctf_comp(meas_info[0], chs);//ToDo Member Function
1204  //
1205  // Load the bad channel list
1206  //
1207  QStringList bads = this->read_bad_channels(p_Node);
1208  //
1209  // Put the data together
1210  //
1211 // info = new FiffInfo();
1212  if (p_Node->id.version != -1)
1213  info.file_id = p_Node->id;
1214  else
1215  info.file_id.version = -1;
1216 
1217  //
1218  // Make the most appropriate selection for the measurement id
1219  //
1220  if (meas_info[0]->parent_id.version == -1)
1221  {
1222  if (meas_info[0]->id.version == -1)
1223  {
1224  if (meas[0]->id.version == -1)
1225  {
1226  if (meas[0]->parent_id.version == -1)
1227  info.meas_id = info.file_id;
1228  else
1229  info.meas_id = meas[0]->parent_id;
1230  }
1231  else
1232  info.meas_id = meas[0]->id;
1233  }
1234  else
1235  info.meas_id = meas_info[0]->id;
1236  }
1237  else
1238  info.meas_id = meas_info[0]->parent_id;
1239 
1240  if (meas_date[0] == -1)
1241  {
1242  info.meas_date[0] = info.meas_id.time.secs;
1243  info.meas_date[1] = info.meas_id.time.usecs;
1244  }
1245  else
1246  {
1247  info.meas_date[0] = meas_date[0];
1248  info.meas_date[1] = meas_date[1];
1249  }
1250 
1251  info.nchan = nchan;
1252  info.sfreq = sfreq;
1253  info.linefreq = linefreq;
1254 
1255  if (highpass != -1.0f)
1256  info.highpass = highpass;
1257  else
1258  info.highpass = 0.0f;
1259 
1260  if (lowpass != -1.0f)
1261  info.lowpass = lowpass;
1262  else
1263  info.lowpass = info.sfreq/2.0;
1264 
1265  //
1266  // Add the channel information and make a list of channel names
1267  // for convenience
1268  //
1269  info.chs = chs;
1270  for (qint32 c = 0; c < info.nchan; ++c)
1271  info.ch_names << info.chs[c].ch_name;
1272 
1273  //
1274  // Add the coordinate transformations
1275  //
1276  info.dev_head_t = dev_head_t;
1277  info.ctf_head_t = ctf_head_t;
1278  if ((!info.dev_head_t.isEmpty()) && (!info.ctf_head_t.isEmpty())) //~isempty(info.dev_head_t) && ~isempty(info.ctf_head_t)
1279  {
1280  info.dev_ctf_t = info.dev_head_t;
1281  info.dev_ctf_t.to = info.ctf_head_t.from;
1282  info.dev_ctf_t.trans = ctf_head_t.trans.inverse()*info.dev_ctf_t.trans;
1283  }
1284  else
1285  info.dev_ctf_t.clear();
1286 
1287  //
1288  // All kinds of auxliary stuff
1289  //
1290  info.dig = dig;
1291  if (!dig_trans.isEmpty())
1292  info.dig_trans = dig_trans;
1293 
1294  info.experimenter = experimenter;
1295  info.description = description;
1296  info.proj_id = proj_id;
1297  info.proj_name = proj_name;
1298  info.xplotter_layout = xplotter_layout;
1299  info.gantry_angle = gantry_angle;
1300  info.utc_offset = utc_offset;
1301 
1302  info.bads = bads;
1303  info.projs = projs;
1304  info.comps = comps;
1305  info.acq_pars = acq_pars;
1306  info.acq_stim = acq_stim;
1307 
1308  p_NodeInfo = meas[0];
1309 
1310  return true;
1311 }
1312 
1313 //=============================================================================================================
1314 
1315 bool FiffStream::read_named_matrix(const FiffDirNode::SPtr& p_Node, fiff_int_t matkind, FiffNamedMatrix& mat)
1316 {
1317  mat.clear();
1318 
1319  FiffDirNode::SPtr node = p_Node;
1320  //
1321  // Descend one level if necessary
1322  //
1323  bool found_it = false;
1324  if (node->type != FIFFB_MNE_NAMED_MATRIX)
1325  {
1326  for (int k = 0; k < node->nchild(); ++k)
1327  {
1328  if (node->children[k]->type == FIFFB_MNE_NAMED_MATRIX)
1329  {
1330  if(node->children[k]->has_tag(matkind))
1331  {
1332  node = node->children[k];
1333  found_it = true;
1334  break;
1335  }
1336  }
1337  }
1338  if (!found_it)
1339  {
1340  qWarning("Fiff::read_named_matrix: Desired named matrix (kind = %d) not available\n",matkind);
1341  return false;
1342  }
1343  }
1344  else
1345  {
1346  if (!node->has_tag(matkind))
1347  {
1348  qWarning("Desired named matrix (kind = %d) not available",matkind);
1349  return false;
1350  }
1351  }
1352 
1353  FiffTag::SPtr t_pTag;
1354  //
1355  // Read everything we need
1356  //
1357  if(!node->find_tag(this, matkind, t_pTag))
1358  {
1359  qWarning("Matrix data missing.\n");
1360  return false;
1361  }
1362  else
1363  {
1364  //qDebug() << "Is Matrix" << t_pTag->isMatrix() << "Special Type:" << t_pTag->getType();
1365  mat.data = t_pTag->toFloatMatrix().cast<double>();
1366  mat.data.transposeInPlace();
1367  }
1368 
1369  mat.nrow = mat.data.rows();
1370  mat.ncol = mat.data.cols();
1371 
1372  if(node->find_tag(this, FIFF_MNE_NROW, t_pTag))
1373  if (*t_pTag->toInt() != mat.nrow)
1374  {
1375  qWarning("Number of rows in matrix data and FIFF_MNE_NROW tag do not match");
1376  return false;
1377  }
1378  if(node->find_tag(this, FIFF_MNE_NCOL, t_pTag))
1379  if (*t_pTag->toInt() != mat.ncol)
1380  {
1381  qWarning("Number of columns in matrix data and FIFF_MNE_NCOL tag do not match");
1382  return false;
1383  }
1384 
1385  QString row_names;
1386  if(node->find_tag(this, FIFF_MNE_ROW_NAMES, t_pTag))
1387  row_names = t_pTag->toString();
1388 
1389  QString col_names;
1390  if(node->find_tag(this, FIFF_MNE_COL_NAMES, t_pTag))
1391  col_names = t_pTag->toString();
1392 
1393  //
1394  // Put it together
1395  //
1396  if (!row_names.isEmpty())
1397  mat.row_names = split_name_list(row_names);
1398 
1399  if (!col_names.isEmpty())
1400  mat.col_names = split_name_list(col_names);
1401 
1402  if (mat.row_names.size() != mat.nrow)
1403  {
1404  qWarning("FiffStream::read_named_matrix - Number of rows in matrix data and row names do not match\n");
1405  }
1406 
1407  if (mat.col_names.size() != mat.ncol)
1408  {
1409  qWarning("FiffStream::read_named_matrix - Number of columns in matrix data and column names do not match\n");
1410  }
1411 
1412  return true;
1413 }
1414 
1415 //=============================================================================================================
1416 
1417 QList<FiffProj> FiffStream::read_proj(const FiffDirNode::SPtr& p_Node)
1418 {
1419  QList<FiffProj> projdata;// = struct('kind',{},'active',{},'desc',{},'data',{});
1420  //
1421  // Locate the projection data
1422  //
1423  QList<FiffDirNode::SPtr> t_qListNodes = p_Node->dir_tree_find(FIFFB_PROJ);
1424  if ( t_qListNodes.size() == 0 )
1425  return projdata;
1426 
1427  FiffTag::SPtr t_pTag;
1428  t_qListNodes[0]->find_tag(this, FIFF_NCHAN, t_pTag);
1429  fiff_int_t global_nchan = 0;
1430  if (t_pTag)
1431  global_nchan = *t_pTag->toInt();
1432 
1433  fiff_int_t nchan;
1434  QList<FiffDirNode::SPtr> t_qListItems = t_qListNodes[0]->dir_tree_find(FIFFB_PROJ_ITEM);
1435  for ( qint32 i = 0; i < t_qListItems.size(); ++i)
1436  {
1437  //
1438  // Find all desired tags in one item
1439  //
1440  FiffDirNode::SPtr t_pFiffDirTreeItem = t_qListItems[i];
1441  t_pFiffDirTreeItem->find_tag(this, FIFF_NCHAN, t_pTag);
1442  if (t_pTag)
1443  nchan = *t_pTag->toInt();
1444  else
1445  nchan = global_nchan;
1446 
1447  t_pFiffDirTreeItem->find_tag(this, FIFF_DESCRIPTION, t_pTag);
1448  QString desc; // maybe, in some cases this has to be a struct.
1449  if (t_pTag)
1450  {
1451  qDebug() << "read_proj: this has to be debugged";
1452  desc = t_pTag->toString();
1453  }
1454  else
1455  {
1456  t_pFiffDirTreeItem->find_tag(this, FIFF_NAME, t_pTag);
1457  if (t_pTag)
1458  desc = t_pTag->toString();
1459  else
1460  {
1461  qWarning("Projection item description missing\n");
1462  return projdata;
1463  }
1464  }
1465 // t_pFiffDirTreeItem->find_tag(this, FIFF_PROJ_ITEM_CH_NAME_LIST, t_pTag);
1466 // QString namelist;
1467 // if (t_pTag)
1468 // {
1469 // namelist = t_pTag->toString();
1470 // }
1471 // else
1472 // {
1473 // printf("Projection item channel list missing\n");
1474 // return projdata;
1475 // }
1476  t_pFiffDirTreeItem->find_tag(this, FIFF_PROJ_ITEM_KIND, t_pTag);
1477  fiff_int_t kind;
1478  if (t_pTag)
1479  {
1480  kind = *t_pTag->toInt();
1481  }
1482  else
1483  {
1484  qWarning("Projection item kind missing");
1485  return projdata;
1486  }
1487  t_pFiffDirTreeItem->find_tag(this, FIFF_PROJ_ITEM_NVEC, t_pTag);
1488  fiff_int_t nvec;
1489  if (t_pTag)
1490  {
1491  nvec = *t_pTag->toInt();
1492  }
1493  else
1494  {
1495  qWarning("Number of projection vectors not specified\n");
1496  return projdata;
1497  }
1498  t_pFiffDirTreeItem->find_tag(this, FIFF_PROJ_ITEM_CH_NAME_LIST, t_pTag);
1499  QStringList names;
1500  if (t_pTag)
1501  {
1502  names = split_name_list(t_pTag->toString());
1503  }
1504  else
1505  {
1506  qWarning("Projection item channel list missing\n");
1507  return projdata;
1508  }
1509  t_pFiffDirTreeItem->find_tag(this, FIFF_PROJ_ITEM_VECTORS, t_pTag);
1510  MatrixXd data;// = NULL;
1511  if (t_pTag)
1512  {
1513  data = t_pTag->toFloatMatrix().cast<double>();
1514  data.transposeInPlace();
1515  }
1516  else
1517  {
1518  qWarning("Projection item data missing\n");
1519  return projdata;
1520  }
1521  t_pFiffDirTreeItem->find_tag(this, FIFF_MNE_PROJ_ITEM_ACTIVE, t_pTag);
1522  bool active;
1523  if (t_pTag)
1524  active = *t_pTag->toInt();
1525  else
1526  active = false;
1527 
1528  if (data.cols() != names.size())
1529  {
1530  qWarning("Number of channel names does not match the size of data matrix\n");
1531  return projdata;
1532  }
1533 
1534  //
1535  // create a named matrix for the data
1536  //
1537  QStringList defaultList;
1538  FiffNamedMatrix t_fiffNamedMatrix(nvec, nchan, defaultList, names, data);
1539 
1540  FiffProj one(kind, active, desc, t_fiffNamedMatrix);
1541  //
1542  projdata.append(one);
1543  }
1544 
1545  if (projdata.size() > 0)
1546  {
1547  printf("\tRead a total of %d projection items:\n", projdata.size());
1548  for(qint32 k = 0; k < projdata.size(); ++k)
1549  {
1550  printf("\t\t%s (%d x %d)",projdata[k].desc.toUtf8().constData(), projdata[k].data->nrow, projdata[k].data->ncol);
1551  if (projdata[k].active)
1552  printf(" active\n");
1553  else
1554  printf(" idle\n");
1555  }
1556  }
1557 
1558  return projdata;
1559 }
1560 
1561 //=============================================================================================================
1562 
1563 bool FiffStream::read_tag_data(FiffTag::SPtr &p_pTag, fiff_long_t pos)
1564 {
1565  if(pos >= 0)
1566  {
1567  this->device()->seek(pos);
1568  }
1569 
1570  if(!p_pTag)
1571  return false;
1572 
1573  //
1574  // Read data when available
1575  //
1576  if (p_pTag->size() > 0)
1577  {
1578  this->readRawData(p_pTag->data(), p_pTag->size());
1580  }
1581 
1582  if (p_pTag->next != FIFFV_NEXT_SEQ)
1583  this->device()->seek(p_pTag->next);//fseek(fid,tag.next,'bof');
1584 
1585  return true;
1586 }
1587 
1588 //=============================================================================================================
1589 
1590 fiff_long_t FiffStream::read_tag_info(FiffTag::SPtr &p_pTag, bool p_bDoSkip)
1591 {
1592  fiff_long_t pos = this->device()->pos();
1593 
1594  p_pTag = FiffTag::SPtr(new FiffTag());
1595 
1596  //Option 1
1597 // t_DataStream.readRawData((char *)p_pTag, FIFFC_TAG_INFO_SIZE);
1598 // p_pTag->kind = Fiff::swap_int(p_pTag->kind);
1599 // p_pTag->type = Fiff::swap_int(p_pTag->type);
1600 // p_pTag->size = Fiff::swap_int(p_pTag->size);
1601 // p_pTag->next = Fiff::swap_int(p_pTag->next);
1602 
1603  //Option 2
1604  *this >> p_pTag->kind;
1605  *this >> p_pTag->type;
1606  qint32 size;
1607  *this >> size;
1608  p_pTag->resize(size);
1609  *this >> p_pTag->next;
1610 
1611 // qDebug() << "read_tag_info" << " Kind:" << p_pTag->kind << " Type:" << p_pTag->type << " Size:" << p_pTag->size() << " Next:" << p_pTag->next;
1612 
1613  if (p_bDoSkip)
1614  {
1615  QTcpSocket* t_qTcpSocket = qobject_cast<QTcpSocket*>(this->device());
1616  if(t_qTcpSocket)
1617  {
1618  this->skipRawData(p_pTag->size());
1619  }
1620  else
1621  {
1622  if (p_pTag->next > 0)
1623  {
1624  if(!this->device()->seek(p_pTag->next)) {
1625  qCritical("fseek"); //fseek(fid,tag.next,'bof');
1626  pos = -1;
1627  }
1628  }
1629  else if (p_pTag->size() > 0 && p_pTag->next == FIFFV_NEXT_SEQ)
1630  {
1631  if(!this->device()->seek(this->device()->pos()+p_pTag->size())) {
1632  qCritical("fseek"); //fseek(fid,tag.size,'cof');
1633  pos = -1;
1634  }
1635  }
1636  }
1637  }
1638  return pos;
1639 }
1640 
1641 //=============================================================================================================
1642 
1644 {
1645  while(this->device()->bytesAvailable() < 16)
1646  this->device()->waitForReadyRead(10);
1647 
1648 // if(!this->read_tag_info(p_pTag, false))
1649 // return false;
1650  this->read_tag_info(p_pTag, false);
1651 
1652  while(this->device()->bytesAvailable() < p_pTag->size())
1653  this->device()->waitForReadyRead(10);
1654 
1655  if(!this->read_tag_data(p_pTag))
1656  return false;
1657 
1658  return true;
1659 }
1660 
1661 //=============================================================================================================
1662 
1664  fiff_long_t pos)
1665 {
1666  if (pos >= 0) {
1667  this->device()->seek(pos);
1668  }
1669 
1670  p_pTag = FiffTag::SPtr(new FiffTag());
1671 
1672  //
1673  // Read fiff tag header from stream
1674  //
1675  *this >> p_pTag->kind;
1676  *this >> p_pTag->type;
1677  qint32 size;
1678  *this >> size;
1679  p_pTag->resize(size);
1680  *this >> p_pTag->next;
1681 
1682 // qDebug() << "read_tag" << " Kind:" << p_pTag->kind << " Type:" << p_pTag->type << " Size:" << p_pTag->size() << " Next:" << p_pTag->next;
1683 
1684  //
1685  // Read data when available
1686  //
1687  int endian;
1688  if (this->byteOrder() == QDataStream::LittleEndian){
1689  endian = FIFFV_LITTLE_ENDIAN;
1690  //printf("Endian: Little\n");
1691  } else {
1692  endian = FIFFV_BIG_ENDIAN;
1693  //printf("Endian: Big\n");
1694  }
1695 
1696  if (p_pTag->size() > 0)
1697  {
1698  this->readRawData(p_pTag->data(), p_pTag->size());
1699  //FiffTag::convert_tag_data(p_pTag,FIFFV_BIG_ENDIAN,FIFFV_NATIVE_ENDIAN);
1701  }
1702 
1703  if (p_pTag->next != FIFFV_NEXT_SEQ)
1704  this->device()->seek(p_pTag->next);//fseek(fid,tag.next,'bof');
1705 
1706  return true;
1707 }
1708 
1709 //=============================================================================================================
1710 
1711 bool FiffStream::setup_read_raw(QIODevice &p_IODevice,
1712  FiffRawData& data,
1713  bool allow_maxshield,
1714  bool is_littleEndian)
1715 {
1716  //
1717  // Open the file
1718  //
1719  FiffStream::SPtr t_pStream(new FiffStream(&p_IODevice));
1720  QString t_sFileName = t_pStream->streamName();
1721 
1722  if(is_littleEndian){
1723  //printf("Setting stream to little Endian\n");
1724  t_pStream->setByteOrder(QDataStream::LittleEndian);
1725  }
1726 
1727  qInfo("Opening raw data %s...\n",t_sFileName.toUtf8().constData());
1728 
1729  if(!t_pStream->open()){
1730  return false;
1731  }
1732 
1733  //
1734  // Read the measurement info
1735  //
1736  FiffInfo info;// = NULL;
1737  FiffDirNode::SPtr meas;
1738  if(!t_pStream->read_meas_info(t_pStream->dirtree(), info, meas))
1739  return false;
1740 
1741  //
1742  // Locate the data of interest
1743  //
1744  QList<FiffDirNode::SPtr> raw = meas->dir_tree_find(FIFFB_RAW_DATA);
1745  if (raw.size() == 0)
1746  {
1747  raw = meas->dir_tree_find(FIFFB_CONTINUOUS_DATA);
1748  if(allow_maxshield)
1749  {
1750 // for (qint32 i = 0; i < raw.size(); ++i)
1751 // if(raw[i])
1752 // delete raw[i];
1753  raw = meas->dir_tree_find(FIFFB_SMSH_RAW_DATA);
1754  qInfo("Maxshield data found\n");
1755 
1756  if (raw.size() == 0)
1757  {
1758  qWarning("No raw data in %s\n", t_sFileName.toUtf8().constData());
1759  return false;
1760  }
1761  }
1762  else
1763  {
1764  if (raw.size() == 0)
1765  {
1766  qWarning("No raw data in %s\n", t_sFileName.toUtf8().constData());
1767  return false;
1768  }
1769  }
1770  }
1771  //
1772  // Set up the output structure
1773  //
1774  info.filename = t_sFileName;
1775 
1776  data.clear();
1777  data.file = t_pStream;// fid;
1778  data.info = info;
1779  data.first_samp = 0;
1780  data.last_samp = 0;
1781  //
1782  // Process the directory
1783  //
1784  QList<FiffDirEntry::SPtr> dir = raw[0]->dir;
1785  fiff_int_t nent = raw[0]->nent();
1786  fiff_int_t nchan = info.nchan;
1787  fiff_int_t first = 0;
1788  fiff_int_t first_samp = 0;
1789  fiff_int_t first_skip = 0;
1790  //
1791  // Get first sample tag if it is there
1792  //
1793  FiffTag::SPtr t_pTag;
1794  if (dir[first]->kind == FIFF_FIRST_SAMPLE)
1795  {
1796  t_pStream->read_tag(t_pTag, dir[first]->pos);
1797  first_samp = *t_pTag->toInt();
1798  ++first;
1799  }
1800  //
1801  // Omit initial skip
1802  //
1803  if (dir[first]->kind == FIFF_DATA_SKIP)
1804  {
1805  //
1806  // This first skip can be applied only after we know the buffer size
1807  //
1808  t_pStream->read_tag(t_pTag, dir[first]->pos);
1809  first_skip = *t_pTag->toInt();
1810  ++first;
1811  }
1812  data.first_samp = first_samp;
1813  //
1814  // Go through the remaining tags in the directory
1815  //
1816  QList<FiffRawDir> rawdir;
1817 // rawdir = struct('ent',{},'first',{},'last',{},'nsamp',{});
1818  fiff_int_t nskip = 0;
1819  fiff_int_t ndir = 0;
1820  fiff_int_t nsamp = 0;
1821  for (qint32 k = first; k < nent; ++k)
1822  {
1823  FiffDirEntry::SPtr ent = dir[k];
1824  if (ent->kind == FIFF_DATA_SKIP)
1825  {
1826  t_pStream->read_tag(t_pTag, ent->pos);
1827  nskip = *t_pTag->toInt();
1828  }
1829  else if(ent->kind == FIFF_DATA_BUFFER)
1830  {
1831  //
1832  // Figure out the number of samples in this buffer
1833  //
1834  switch(ent->type)
1835  {
1836  case FIFFT_DAU_PACK16:
1837  nsamp = ent->size/(2*nchan);
1838  break;
1839  case FIFFT_SHORT:
1840  nsamp = ent->size/(2*nchan);
1841  break;
1842  case FIFFT_FLOAT:
1843  nsamp = ent->size/(4*nchan);
1844  break;
1845  case FIFFT_INT:
1846  nsamp = ent->size/(4*nchan);
1847  break;
1848  default:
1849  qWarning("Cannot handle data buffers of type %d\n",ent->type);
1850  return false;
1851  }
1852  //
1853  // Do we have an initial skip pending?
1854  //
1855  if (first_skip > 0)
1856  {
1857  first_samp += nsamp*first_skip;
1858  data.first_samp = first_samp;
1859  first_skip = 0;
1860  }
1861  //
1862  // Do we have a skip pending?
1863  //
1864  if (nskip > 0)
1865  {
1866  FiffRawDir t_RawDir;
1867  t_RawDir.first = first_samp;
1868  t_RawDir.last = first_samp + nskip*nsamp - 1;//ToDo -1 right or is that MATLAB syntax
1869  t_RawDir.nsamp = nskip*nsamp;
1870  rawdir.append(t_RawDir);
1871  first_samp = first_samp + nskip*nsamp;
1872  nskip = 0;
1873  ++ndir;
1874  }
1875  //
1876  // Add a data buffer
1877  //
1878  FiffRawDir t_RawDir;
1879  t_RawDir.ent = ent;
1880  t_RawDir.first = first_samp;
1881  t_RawDir.last = first_samp + nsamp - 1;//ToDo -1 right or is that MATLAB syntax
1882  t_RawDir.nsamp = nsamp;
1883  rawdir.append(t_RawDir);
1884  first_samp += nsamp;
1885  ++ndir;
1886  }
1887  }
1888  data.last_samp = first_samp - 1;//ToDo -1 right or is that MATLAB syntax
1889  //
1890  // Add the calibration factors
1891  //
1892  RowVectorXd cals(data.info.nchan);
1893  cals.setZero();
1894  for (qint32 k = 0; k < data.info.nchan; ++k)
1895  cals[k] = data.info.chs[k].range*data.info.chs[k].cal;
1896  //
1897  data.cals = cals;
1898  data.rawdir = rawdir;
1899  //data->proj = [];
1900  //data.comp = [];
1901  //
1902  qInfo("\tRange : %d ... %d = %9.3f ... %9.3f secs",
1903  data.first_samp,data.last_samp,
1904  (double)data.first_samp/data.info.sfreq,
1905  (double)data.last_samp/data.info.sfreq);
1906  qInfo("Ready.");
1907  data.file->close();
1908 
1909  return true;
1910 }
1911 
1912 //=============================================================================================================
1913 
1914 QStringList FiffStream::split_name_list(QString p_sNameList)
1915 {
1916  return p_sNameList.replace(" ","").split(":");
1917 }
1918 
1919 //=============================================================================================================
1920 
1921 fiff_long_t FiffStream::start_block(fiff_int_t kind)
1922 {
1923  return this->write_int(FIFF_BLOCK_START,&kind);
1924 }
1925 
1926 //=============================================================================================================
1927 
1929 {
1930  FiffStream::SPtr p_pStream(new FiffStream(&p_IODevice));
1931  QString t_sFileName = p_pStream->streamName();
1932 
1933  if(!p_pStream->device()->open(QIODevice::WriteOnly))
1934  {
1935  qWarning("Cannot write to %s\n", t_sFileName.toUtf8().constData());//consider throw
1936  FiffStream::SPtr p_pEmptyStream;
1937  return p_pEmptyStream;
1938  }
1939 
1940  //
1941  // Write the compulsory items
1942  //
1943  p_pStream->write_id(FIFF_FILE_ID);//1
1944  int null_pointer = FIFFV_NEXT_NONE;
1945  p_pStream->write_int(FIFF_DIR_POINTER,&null_pointer);//2
1946  p_pStream->write_int(FIFF_FREE_LIST,&null_pointer);//3
1947  //
1948  // Ready for more
1949  //
1950  return p_pStream;
1951 }
1952 
1953 //=============================================================================================================
1954 
1956 {
1957 
1958  FiffStream::SPtr t_pStream(new FiffStream(&p_IODevice));
1959  QString t_sFileName = t_pStream->streamName();
1960 
1961  /*
1962  * Try to open...
1963  */
1964  if(!t_pStream->open(QIODevice::ReadWrite)) {
1965  qCritical("Cannot open %s\n", t_sFileName.toUtf8().constData());//consider throw
1966  return FiffStream::SPtr();
1967  }
1968 
1969  FiffTag::SPtr t_pTag;
1970  long dirpos,pointerpos;
1971 
1972  QFile *file = qobject_cast<QFile *>(t_pStream->device());
1973 
1974  if (file != NULL) {
1975  /*
1976  * Ensure that the last tag in the directory has next set to FIFF_NEXT_NONE
1977  */
1978  pointerpos = t_pStream->dir()[t_pStream->nent()-2]->pos;
1979  if(!t_pStream->read_tag(t_pTag,pointerpos)){
1980  qCritical("Could not read last tag in the directory list!");
1981  t_pStream->close();
1982  return FiffStream::SPtr();
1983  }
1984  if (t_pTag->next != FIFFV_NEXT_NONE) {
1985  t_pTag->next = FIFFV_NEXT_NONE;
1986  t_pStream->write_tag(t_pTag,pointerpos);
1987  }
1988  /*
1989  * Read directory pointer
1990  */
1991  pointerpos = t_pStream->dir()[1]->pos;
1992  if(!t_pStream->read_tag(t_pTag,pointerpos)){
1993  qCritical("Could not read directory pointer!");
1994  t_pStream->close();
1995  return FiffStream::SPtr();
1996  }
1997  /*
1998  * Do we have a directory?
1999  */
2000  dirpos = *t_pTag->toInt();
2001  if (dirpos > 0) {
2002  /*
2003  * Yes! We will ignore it.
2004  */
2005  t_pStream->write_dir_pointer(-1, pointerpos);
2006  /*
2007  * Clean up the trailing end
2008  */
2009  file->resize(dirpos);//truncate file to new size
2010  }
2011  /*
2012  * Seek to end for writing
2013  */
2014  t_pStream->device()->seek(file->size());//SEEK_END
2015  }
2016  return t_pStream;
2017 }
2018 
2019 //=============================================================================================================
2020 
2022  const FiffInfo& info,
2023  RowVectorXd& cals,
2024  MatrixXi sel,
2025  bool bResetRange)
2026 {
2027  //
2028  // We will always write floats
2029  //
2030  fiff_int_t data_type = 4;
2031  qint32 k;
2032 
2033  if(sel.cols() == 0)
2034  {
2035  sel.resize(1,info.nchan);
2036  for (k = 0; k < info.nchan; ++k)
2037  sel(0, k) = k; //+1 when MATLAB notation
2038  }
2039 
2040  QList<FiffChInfo> chs;
2041 
2042  for(k = 0; k < sel.cols(); ++k)
2043  chs << info.chs.at(sel(0,k));
2044 
2045  fiff_int_t nchan = chs.size();
2046 
2047  //
2048  // Create the file and save the essentials
2049  //
2050  FiffStream::SPtr t_pStream = start_file(p_IODevice);//1, 2, 3
2051  t_pStream->start_block(FIFFB_MEAS);//4
2052  t_pStream->write_id(FIFF_BLOCK_ID);//5
2053  if(info.meas_id.version != -1)
2054  {
2055  t_pStream->write_id(FIFF_PARENT_BLOCK_ID,info.meas_id);//6
2056  }
2057  //
2058  //
2059  // Measurement info
2060  //
2061  t_pStream->start_block(FIFFB_MEAS_INFO);//7
2062 
2063  #ifndef WASMBUILD
2064  //
2065  // Blocks from the original
2066  //
2067  QList<fiff_int_t> blocks;
2068  blocks << FIFFB_SUBJECT << FIFFB_HPI_MEAS << FIFFB_HPI_RESULT << FIFFB_HPI_SUBSYSTEM << FIFFB_ISOTRAK << FIFFB_PROCESSING_HISTORY << FIFFB_DACQ_PARS << FIFFB_EVENTS;
2069  bool have_hpi_result = false;
2070  bool have_isotrak = false;
2071  if (blocks.size() > 0 && !info.filename.isEmpty())
2072  {
2073  QFile t_qFile(info.filename);//ToDo this has to be adapted for TCPSocket
2074  FiffStream::SPtr t_pStream2(new FiffStream(&t_qFile));
2075 
2076  if(!t_pStream2->open()){
2077  qDebug() << "Failed to open file. Returning early";
2078  return t_pStream;
2079  }
2080 
2081  for(qint32 k = 0; k < blocks.size(); ++k)
2082  {
2083  QList<FiffDirNode::SPtr> nodes = t_pStream2->dirtree()->dir_tree_find(blocks[k]);
2084  FiffDirNode::copy_tree(t_pStream2,t_pStream2->dirtree()->id,nodes,t_pStream);
2085  if(blocks[k] == FIFFB_HPI_RESULT && nodes.size() > 0)
2086  have_hpi_result = true;
2087 
2088  if(blocks[k] == FIFFB_ISOTRAK && nodes.size() > 0)
2089  have_isotrak = true;
2090  }
2091 
2092  t_pStream2 = FiffStream::SPtr();
2093  }
2094  #endif
2095 
2096  //
2097  // megacq parameters
2098  //
2099  if (!info.acq_pars.isEmpty() || !info.acq_stim.isEmpty())
2100  {
2101  t_pStream->start_block(FIFFB_DACQ_PARS);
2102  if (!info.acq_pars.isEmpty())
2103  t_pStream->write_string(FIFF_DACQ_PARS, info.acq_pars);
2104 
2105  if (!info.acq_stim.isEmpty())
2106  t_pStream->write_string(FIFF_DACQ_STIM, info.acq_stim);
2107 
2108  t_pStream->end_block(FIFFB_DACQ_PARS);
2109  }
2110 
2111  #ifndef WASMBUILD
2112  //
2113  // Coordinate transformations if the HPI result block was not there
2114  //
2115  if (!have_hpi_result)
2116  {
2117  if (!info.dev_head_t.isEmpty())
2118  t_pStream->write_coord_trans(info.dev_head_t);
2119 
2120  if (!info.ctf_head_t.isEmpty())
2121  t_pStream->write_coord_trans(info.ctf_head_t);
2122  }
2123  //
2124  // Polhemus data
2125  //
2126  if (info.dig.size() > 0 && !have_isotrak)
2127  {
2128  t_pStream->start_block(FIFFB_ISOTRAK);
2129  for (qint32 k = 0; k < info.dig.size(); ++k)
2130  t_pStream->write_dig_point(info.dig[k]);
2131 
2132  t_pStream->end_block(FIFFB_ISOTRAK);
2133  }
2134  #endif
2135 
2136  //
2137  // Projectors
2138  //
2139  t_pStream->write_proj(info.projs);
2140  //
2141  // CTF compensation info
2142  //
2143  t_pStream->write_ctf_comp(info.comps);
2144  //
2145  // Bad channels
2146  //
2147  if (info.bads.size() > 0)
2148  {
2149  t_pStream->start_block(FIFFB_MNE_BAD_CHANNELS);
2150  t_pStream->write_name_list(FIFF_MNE_CH_NAME_LIST,info.bads);
2151  t_pStream->end_block(FIFFB_MNE_BAD_CHANNELS);
2152  }
2153  //
2154  // General
2155  //
2156  t_pStream->write_float(FIFF_SFREQ,&info.sfreq);
2157  t_pStream->write_float(FIFF_HIGHPASS,&info.highpass);
2158  t_pStream->write_float(FIFF_LOWPASS,&info.lowpass);
2159  t_pStream->write_float(FIFF_LINE_FREQ,&info.linefreq);
2160  t_pStream->write_int(FIFF_GANTRY_ANGLE,&info.gantry_angle);
2161  t_pStream->write_int(FIFF_NCHAN,&nchan);
2162  t_pStream->write_int(FIFF_DATA_PACK,&data_type);
2163  t_pStream->write_int(FIFF_PROJ_ID,&info.proj_id);
2164  t_pStream->write_string(FIFF_EXPERIMENTER,info.experimenter);
2165  t_pStream->write_string(FIFF_DESCRIPTION,info.description);
2166  t_pStream->write_string(FIFF_PROJ_NAME,info.proj_name);
2167  t_pStream->write_string(FIFF_XPLOTTER_LAYOUT,info.xplotter_layout);
2168  if (info.meas_date[0] != -1)
2169  t_pStream->write_int(FIFF_MEAS_DATE,info.meas_date, 2);
2170  //
2171  // Channel info
2172  //
2173  cals = RowVectorXd(nchan);
2174  for(k = 0; k < nchan; ++k)
2175  {
2176  //
2177  // Scan numbers may have been messed up
2178  //
2179  chs[k].scanNo = k+1;
2180  if(bResetRange) {
2181  chs[k].range = 1.0; // Reset to 1.0 because we always write floats.
2182  }
2183  cals[k] = chs[k].cal;
2184  t_pStream->write_ch_info(chs[k]);
2185  }
2186  //
2187  //
2188  t_pStream->end_block(FIFFB_MEAS_INFO);
2189  //
2190  // Start the raw data
2191  //
2192  t_pStream->start_block(FIFFB_RAW_DATA);
2193 
2194  return t_pStream;
2195 }
2196 
2197 //=============================================================================================================
2198 
2199 fiff_long_t FiffStream::write_tag(const QSharedPointer<FiffTag> &p_pTag, fiff_long_t pos)
2200 {
2201  /*
2202  * Write tag to specified position
2203  */
2204  if (pos >= 0) {
2205  this->device()->seek(pos);
2206  }
2207  else { //SEEK_END
2208  QFile* file = qobject_cast<QFile*> (this->device());
2209  if(file)
2210  this->device()->seek(file->size());
2211  }
2212  pos = this->device()->pos();
2213 
2214  fiff_int_t datasize = p_pTag->size();
2215 
2216  *this << static_cast<qint32>(p_pTag->kind);
2217  *this << static_cast<qint32>(p_pTag->type);
2218  *this << static_cast<qint32>(datasize);
2219  *this << static_cast<qint32>(p_pTag->next);
2220 
2221  /*
2222  * Do we have data?
2223  */
2224  if (datasize > 0) {
2225  /*
2226  * Data exists...
2227  */
2228  this->writeRawData(p_pTag->data(),datasize);
2229  }
2230 
2231  return pos;
2232 }
2233 
2234 //=============================================================================================================
2235 
2237 {
2238  fiff_long_t pos = this->device()->pos();
2239 
2240  //typedef struct _fiffChPosRec {
2241  // fiff_int_t coil_type; /*!< What kind of coil. */
2242  // fiff_float_t r0[3]; /*!< Coil coordinate system origin */
2243  // fiff_float_t ex[3]; /*!< Coil coordinate system x-axis unit vector */
2244  // fiff_float_t ey[3]; /*!< Coil coordinate system y-axis unit vector */
2245  // fiff_float_t ez[3]; /*!< Coil coordinate system z-axis unit vector */
2246  //} fiffChPosRec,*fiffChPos; /*!< Measurement channel position and coil type */
2247 
2248  //typedef struct _fiffChInfoRec {
2249  // fiff_int_t scanNo; /*!< Scanning order # */
2250  // fiff_int_t logNo; /*!< Logical channel # */
2251  // fiff_int_t kind; /*!< Kind of channel */
2252  // fiff_float_t range; /*!< Voltmeter range (only applies to raw data ) */
2253  // fiff_float_t cal; /*!< Calibration from volts to... */
2254  // fiff_ch_pos_t chpos; /*!< Channel location */
2255  // fiff_int_t unit; /*!< Unit of measurement */
2256  // fiff_int_t unit_mul; /*!< Unit multiplier exponent */
2257  // fiff_char_t ch_name[16]; /*!< Descriptive name for the channel */
2258  //} fiffChInfoRec,*fiffChInfo; /*!< Description of one channel */
2259  fiff_int_t datasize= 4*13 + 4*7 + 16;
2260 
2261  *this << (qint32)FIFF_CH_INFO;
2262  *this << (qint32)FIFFT_CH_INFO_STRUCT;
2263  *this << (qint32)datasize;
2264  *this << (qint32)FIFFV_NEXT_SEQ;
2265 
2266  //
2267  // Start writing fiffChInfoRec
2268  //
2269  *this << (qint32)ch.scanNo;
2270  *this << (qint32)ch.logNo;
2271  *this << (qint32)ch.kind;
2272 
2273  *this << ch.range;
2274  *this << ch.cal;
2275 
2276  //
2277  // FiffChPos follows
2278  //
2279  write_ch_pos(ch.chpos);
2280 
2281  //
2282  // unit and unit multiplier
2283  //
2284  *this << (qint32)ch.unit;
2285  *this << (qint32)ch.unit_mul;
2286 
2287  //
2288  // Finally channel name
2289  //
2290  fiff_int_t len = ch.ch_name.size();
2291  QString ch_name;
2292  if(len > 15)
2293  ch_name = ch.ch_name.mid(0, 15);
2294  else
2295  ch_name = ch.ch_name;
2296 
2297  len = ch_name.size();
2298 
2299  this->writeRawData(ch_name.toUtf8().constData(),len);
2300 
2301  if (len < 16) {
2302  const char* chNull = "";
2303  for(qint32 i = 0; i < 16-len; ++i)
2304  this->writeRawData(chNull,1);
2305  }
2306 
2307  return pos;
2308 }
2309 
2310 //=============================================================================================================
2311 
2312 fiff_long_t FiffStream::write_ch_pos(const FiffChPos &chpos)
2313 {
2314  fiff_long_t pos = this->device()->pos();
2315 
2316  //
2317  // FiffChPos
2318  //
2319  *this << (qint32)chpos.coil_type;
2320 
2321  qint32 i;
2322  // r0
2323  for(i = 0; i < 3; ++i)
2324  *this << chpos.r0[i];
2325  // ex
2326  for(i = 0; i < 3; ++i)
2327  *this << chpos.ex[i];
2328  // ey
2329  for(i = 0; i < 3; ++i)
2330  *this << chpos.ey[i];
2331  // ez
2332  for(i = 0; i < 3; ++i)
2333  *this << chpos.ez[i];
2334 
2335  return pos;
2336 }
2337 
2338 //=============================================================================================================
2339 
2341 {
2342  fiff_long_t pos = this->device()->pos();
2343 
2344  //?typedef struct _fiffCoordTransRec {
2345  // fiff_int_t from; /*!< Source coordinate system. */
2346  // fiff_int_t to; /*!< Destination coordinate system. */
2347  // fiff_float_t rot[3][3]; /*!< The forward transform (rotation part) */
2348  // fiff_float_t move[3]; /*!< The forward transform (translation part) */
2349  // fiff_float_t invrot[3][3]; /*!< The inverse transform (rotation part) */
2350  // fiff_float_t invmove[3]; /*!< The inverse transform (translation part) */
2351  //} *fiffCoordTrans, fiffCoordTransRec; /*!< Coordinate transformation descriptor */
2352  fiff_int_t datasize = 4*2*12 + 4*2;
2353 
2354  *this << (qint32)FIFF_COORD_TRANS;
2355  *this << (qint32)FIFFT_COORD_TRANS_STRUCT;
2356  *this << (qint32)datasize;
2357  *this << (qint32)FIFFV_NEXT_SEQ;
2358 
2359  //
2360  // Start writing fiffCoordTransRec
2361  //
2362  *this << (qint32)trans.from;
2363  *this << (qint32)trans.to;
2364 
2365  //
2366  // The transform...
2367  //
2368  qint32 r, c;
2369  for (r = 0; r < 3; ++r)
2370  for (c = 0; c < 3; ++c)
2371  *this << (float)trans.trans(r,c);
2372  for (r = 0; r < 3; ++r)
2373  *this << (float)trans.trans(r,3);
2374 
2375  //
2376  // ...and its inverse
2377  //
2378  for (r = 0; r < 3; ++r)
2379  for (c = 0; c < 3; ++c)
2380  *this << (float)trans.invtrans(r,c);
2381  for (r = 0; r < 3; ++r)
2382  *this << (float)trans.invtrans(r,3);
2383 
2384  return pos;
2385 }
2386 
2387 //=============================================================================================================
2388 
2389 fiff_long_t FiffStream::write_cov(const FiffCov &p_FiffCov)
2390 {
2391  fiff_long_t pos = this->device()->pos();
2392 
2393  this->start_block(FIFFB_MNE_COV);
2394 
2395  //
2396  // Dimensions etc.
2397  //
2398  this->write_int(FIFF_MNE_COV_KIND, &p_FiffCov.kind);
2399  this->write_int(FIFF_MNE_COV_DIM, &p_FiffCov.dim);
2400  if (p_FiffCov.nfree > 0)
2401  this->write_int(FIFF_MNE_COV_NFREE, &p_FiffCov.nfree);
2402  //
2403  // Channel names
2404  //
2405  if(p_FiffCov.names.size() > 0)
2406  this->write_name_list(FIFF_MNE_ROW_NAMES, p_FiffCov.names);
2407  //
2408  // Data
2409  //
2410  if(p_FiffCov.diag)
2411  this->write_double(FIFF_MNE_COV_DIAG, p_FiffCov.data.col(0).data(), p_FiffCov.data.rows());
2412  else
2413  {
2414 // if issparse(cov.data)
2415 // fiff_write_float_sparse_rcs(fid,FIFF.FIFF_MNE_COV,cov.data);
2416 // else
2417 // {
2418  // Store only lower part of covariance matrix
2419  qint32 dim = p_FiffCov.dim;
2420  qint32 n = ((dim*dim) - dim)/2;
2421 
2422  VectorXd vals(n);
2423  qint32 count = 0;
2424  for(qint32 i = 1; i < dim; ++i)
2425  for(qint32 j = 0; j < i; ++j)
2426  vals(count) = p_FiffCov.data(i,j);
2427 
2428  this->write_double(FIFF_MNE_COV, vals.data(), vals.size());
2429 // }
2430  }
2431  //
2432  // Eigenvalues and vectors if present
2433  //
2434  if(p_FiffCov.eig.size() > 0 && p_FiffCov.eigvec.size() > 0)
2435  {
2436  this->write_float_matrix(FIFF_MNE_COV_EIGENVECTORS, p_FiffCov.eigvec.cast<float>());
2437  this->write_double(FIFF_MNE_COV_EIGENVALUES, p_FiffCov.eig.data(), p_FiffCov.eig.size());
2438  }
2439  //
2440  // Projection operator
2441  //
2442  this->write_proj(p_FiffCov.projs);
2443  //
2444  // Bad channels
2445  //
2446  if(p_FiffCov.bads.size() > 0)
2447  {
2448  this->start_block(FIFFB_MNE_BAD_CHANNELS);
2449  this->write_name_list(FIFF_MNE_CH_NAME_LIST, p_FiffCov.bads);
2450  this->end_block(FIFFB_MNE_BAD_CHANNELS);
2451  }
2452  //
2453  // Done!
2454  //
2455  this->end_block(FIFFB_MNE_COV);
2456 
2457  return pos;
2458 }
2459 
2460 //=============================================================================================================
2461 
2462 fiff_long_t FiffStream::write_ctf_comp(const QList<FiffCtfComp>& comps)
2463 {
2464  fiff_long_t pos = this->device()->pos();
2465 
2466  if (comps.size() <= 0)
2467  return -1;
2468  //
2469  // This is very simple in fact
2470  //
2471  this->start_block(FIFFB_MNE_CTF_COMP);
2472  for(qint32 k = 0; k < comps.size(); ++k)
2473  {
2474  FiffCtfComp comp(comps[k]);
2475  this->start_block(FIFFB_MNE_CTF_COMP_DATA);
2476  //
2477  // Write the compensation kind
2478  //
2480  qint32 save_calibrated = comp.save_calibrated;
2481  this->write_int(FIFF_MNE_CTF_COMP_CALIBRATED, &save_calibrated);
2482  //
2483  // Write an uncalibrated or calibrated matrix
2484  // If compensators where calibrated undo this here
2485  //
2486  if(comps[k].save_calibrated) {
2487  comp.data->data = (comp.rowcals.asDiagonal()).inverse()* comp.data->data * (comp.colcals.asDiagonal()).inverse();
2488  }
2489 
2490  this->write_named_matrix(FIFF_MNE_CTF_COMP_DATA,*comp.data.data());
2491  this->end_block(FIFFB_MNE_CTF_COMP_DATA);
2492  }
2493  this->end_block(FIFFB_MNE_CTF_COMP);
2494 
2495  return pos;
2496 }
2497 
2498 //=============================================================================================================
2499 
2501 {
2502  fiff_long_t pos = this->device()->pos();
2503 
2504  //?typedef struct _fiffDigPointRec {
2505  // fiff_int_t kind; /*!< FIFF_POINT_CARDINAL,
2506  // * FIFF_POINT_HPI, or
2507  // * FIFF_POINT_EEG */
2508  // fiff_int_t ident; /*!< Number identifying this point */
2509  // fiff_float_t r[3]; /*!< Point location */
2510  //} *fiffDigPoint,fiffDigPointRec; /*!< Digitization point description */
2511  fiff_int_t datasize = 5*4;
2512 
2513  *this << (qint32)FIFF_DIG_POINT;
2514  *this << (qint32)FIFFT_DIG_POINT_STRUCT;
2515  *this << (qint32)datasize;
2516  *this << (qint32)FIFFV_NEXT_SEQ;
2517 
2518  //
2519  // Start writing fiffDigPointRec
2520  //
2521  *this << (qint32)dig.kind;
2522  *this << (qint32)dig.ident;
2523  for(qint32 i = 0; i < 3; ++i)
2524  *this << dig.r[i];
2525 
2526  return pos;
2527 }
2528 
2529 //=============================================================================================================
2530 
2531 fiff_long_t FiffStream::write_dir_pointer(fiff_int_t dirpos, fiff_long_t pos, fiff_int_t next)
2532 {
2533  /*
2534  * Write entires to specified position
2535  */
2536  if (pos >= 0) {
2537  this->device()->seek(pos);
2538  }
2539  else { //SEEK_END
2540  QFile* file = qobject_cast<QFile*> (this->device());
2541  if(file)
2542  this->device()->seek(file->size());
2543  }
2544  pos = this->device()->pos();
2545 
2546  fiff_int_t datasize = 1 * 4;
2547 
2548  *this << (qint32)FIFF_DIR_POINTER;
2549  *this << (qint32)FIFFT_INT;
2550  *this << (qint32)datasize;
2551  *this << (qint32)next;
2552 
2553  *this << dirpos;
2554 
2555  return pos;
2556 }
2557 
2558 //=============================================================================================================
2559 
2560 fiff_long_t FiffStream::write_dir_entries(const QList<FiffDirEntry::SPtr> &dir, fiff_long_t pos)
2561 {
2562 // /** Directories are composed of these structures. *
2563 // typedef struct _fiffDirEntryRec {
2564 // fiff_int_t kind; /**< Tag number *
2565 // fiff_int_t type; /**< Data type *
2566 // fiff_int_t size; /**< How many bytes *
2567 // fiff_int_t pos; /**< Location in file
2568 // * Note: the data is located at pos +
2569 // * FIFFC_DATA_OFFSET *
2570 // } fiffDirEntryRec,*fiffDirEntry;/**< Directory is composed of these *
2571 
2572  /*
2573  * Write entires to specified position
2574  */
2575  if (pos >= 0) {
2576  this->device()->seek(pos);
2577  }
2578  else { //SEEK_END
2579  QFile* file = qobject_cast<QFile*> (this->device());
2580  if(file)
2581  this->device()->seek(file->size());
2582  }
2583 
2584  pos = this->device()->pos();
2585 
2586  fiff_int_t nent = dir.size();
2587  fiff_int_t datasize = nent * (fiff_int_t)sizeof(FiffDirEntry);
2588 
2589  *this << (qint32)FIFF_DIR;
2590  *this << (qint32)FIFFT_DIR_ENTRY_STRUCT;
2591  *this << (qint32)datasize;
2592  *this << (qint32)FIFFV_NEXT_NONE;
2593 
2594  //
2595  // Start writing FiffDirEntries
2596  //
2597  for(qint32 i = 0; i < nent; ++i) {
2598  *this << (qint32)dir[i]->kind;
2599  *this << (qint32)dir[i]->type;
2600  *this << (qint32)dir[i]->size;
2601  *this << (qint32)dir[i]->pos;
2602  }
2603 
2604  return pos;
2605 }
2606 
2607 //=============================================================================================================
2608 
2609 fiff_long_t FiffStream::write_double(fiff_int_t kind, const double* data, fiff_int_t nel)
2610 {
2611  fiff_long_t pos = this->device()->pos();
2612 
2613  qint32 datasize = nel * 8;
2614 
2615  *this << (qint32)kind;
2616  *this << (qint32)FIFFT_DOUBLE;
2617  *this << (qint32)datasize;
2618  *this << (qint32)FIFFV_NEXT_SEQ;
2619 
2620  for(qint32 i = 0; i < nel; ++i)
2621  *this << data[i];
2622 
2623  return pos;
2624 }
2625 
2626 //=============================================================================================================
2627 
2628 fiff_long_t FiffStream::write_float(fiff_int_t kind, const float* data, fiff_int_t nel)
2629 {
2630  fiff_long_t pos = this->device()->pos();
2631 
2632  qint32 datasize = nel * 4;
2633 
2634  *this << (qint32)kind;
2635  *this << (qint32)FIFFT_FLOAT;
2636  *this << (qint32)datasize;
2637  *this << (qint32)FIFFV_NEXT_SEQ;
2638 
2639  for(qint32 i = 0; i < nel; ++i)
2640  *this << data[i];
2641 
2642  return pos;
2643 }
2644 
2645 //=============================================================================================================
2646 
2647 fiff_long_t FiffStream::write_float_matrix(fiff_int_t kind, const MatrixXf& mat)
2648 {
2649  fiff_long_t pos = this->device()->pos();
2650 
2651  qint32 numel = mat.rows() * mat.cols();
2652 
2653  fiff_int_t datasize = 4*numel + 4*3;
2654 
2655  *this << (qint32)kind;
2656  *this << (qint32)FIFFT_MATRIX_FLOAT;
2657  *this << (qint32)datasize;
2658  *this << (qint32)FIFFV_NEXT_SEQ;
2659 
2660  qint32 i, j;
2661  // Storage order: row-major
2662  for(i = 0; i < mat.rows(); ++i)
2663  for(j = 0; j < mat.cols(); ++j)
2664  *this << mat(i,j);
2665 
2666  qint32 dims[3];
2667  dims[0] = mat.cols();
2668  dims[1] = mat.rows();
2669  dims[2] = 2;
2670 
2671  for(i = 0; i < 3; ++i)
2672  *this << dims[i];
2673 
2674  return pos;
2675 }
2676 
2677 //=============================================================================================================
2678 
2679 fiff_long_t FiffStream::write_float_sparse_ccs(fiff_int_t kind, const SparseMatrix<float>& mat)
2680 {
2681  fiff_long_t pos = this->device()->pos();
2682 
2683  //
2684  // nnz values
2685  // nnz row indices
2686  // ncol+1 pointers
2687  // dims
2688  // nnz
2689  // ndim
2690  //
2691  qint32 nnzm = mat.nonZeros();
2692  qint32 ncol = mat.cols();
2693  fiff_int_t datasize = 4*nnzm + 4*nnzm + 4*(ncol+1) + 4*4;
2694  //
2695  // Nonzero entries
2696  //
2697  typedef Eigen::Triplet<float> T;
2698  std::vector<T> s;
2699  s.reserve(mat.nonZeros());
2700  for (int k=0; k < mat.outerSize(); ++k)
2701  for (SparseMatrix<float>::InnerIterator it(mat,k); it; ++it)
2702  s.push_back(T(it.row(), it.col(), it.value()));
2703 
2704  s = MNEMath::sortrows<float>(s, 1);
2705 
2706  //[ rows, starts ] = unique(s(:,1),'first');
2707  std::vector<qint32> cols, starts;
2708  qint32 v_old = -1;
2709  quint32 i;
2710  for(i = 0; i < s.size(); ++i)
2711  {
2712  if((signed) s[i].col() != v_old)
2713  {
2714  v_old = s[i].col();
2715  cols.push_back(s[i].col());
2716  starts.push_back(i);
2717  }
2718  }
2719 
2720  *this << (qint32)kind;
2721  *this << (qint32)FIFFT_CCS_MATRIX_FLOAT;
2722  *this << (qint32)datasize;
2723  *this << (qint32)FIFFV_NEXT_SEQ;
2724 
2725  //
2726  // The data values
2727  //
2728  for(i = 0; i < s.size(); ++i)
2729  *this << s[i].value();
2730 
2731  //
2732  // Row indices
2733  //
2734  for(i = 0; i < s.size(); ++i)
2735  *this << s[i].row();
2736 
2737  //
2738  // Pointers
2739  //
2740  RowVectorXi ptrs = RowVectorXi::Ones(ncol+1);
2741  ptrs.array() *= -1;
2742  quint32 k;
2743  for(k = 0; k < cols.size(); ++k)
2744  ptrs[cols[k]] = starts[k];
2745  ptrs[ncol] = nnzm;
2746  //
2747  // Fill in pointers for empty columns
2748  //
2749  for(k = ncol; k >= 1; --k)
2750  if(ptrs[k-1] < 0)
2751  ptrs[k-1] = ptrs[k];
2752  //
2753  for(i = 0; i < (quint32)ptrs.size(); ++i)
2754  *this << ptrs[i];
2755  //
2756  // Dimensions
2757  //
2758  qint32 dims[4];
2759  dims[0] = mat.nonZeros();
2760  dims[1] = mat.rows();
2761  dims[2] = mat.cols();
2762  dims[3] = 2;
2763 
2764  for(i = 0; i < 4; ++i)
2765  *this << dims[i];
2766 
2767  return pos;
2768 }
2769 
2770 //=============================================================================================================
2771 
2772 fiff_long_t FiffStream::write_float_sparse_rcs(fiff_int_t kind, const SparseMatrix<float>& mat)
2773 {
2774  fiff_long_t pos = this->device()->pos();
2775 
2776  //
2777  // nnz values
2778  // nnz column indices
2779  // nrow+1 pointers
2780  // dims
2781  // nnz
2782  // ndim
2783  //
2784  qint32 nnzm = mat.nonZeros();
2785  qint32 nrow = mat.rows();
2786  fiff_int_t datasize = 4*nnzm + 4*nnzm + 4*(nrow+1) + 4*4;
2787  //
2788  // Nonzero entries
2789  //
2790  typedef Eigen::Triplet<float> T;
2791  std::vector<T> s;
2792  s.reserve(mat.nonZeros());
2793  for (int k=0; k < mat.outerSize(); ++k)
2794  for (SparseMatrix<float>::InnerIterator it(mat,k); it; ++it)
2795  s.push_back(T(it.row(), it.col(), it.value()));
2796 
2797  s = MNEMath::sortrows<float>(s);
2798 
2799  //[ rows, starts ] = unique(s(:,1),'first');
2800  std::vector<qint32> rows, starts;
2801  qint32 v_old = -1;
2802  quint32 i;
2803  for(i = 0; i < s.size(); ++i)
2804  {
2805  if((signed) s[i].row() != v_old)
2806  {
2807  v_old = s[i].row();
2808  rows.push_back(s[i].row());
2809  starts.push_back(i);
2810  }
2811  }
2812 
2813  //
2814  // Write tag info header
2815  //
2816  *this << (qint32)kind;
2817  *this << (qint32)FIFFT_RCS_MATRIX_FLOAT;
2818  *this << (qint32)datasize;
2819  *this << (qint32)FIFFV_NEXT_SEQ;
2820 
2821  //
2822  // The data values
2823  //
2824  for(i = 0; i < s.size(); ++i)
2825  *this << s[i].value();
2826 
2827  //
2828  // Column indices
2829  //
2830  for(i = 0; i < s.size(); ++i)
2831  *this << s[i].col();
2832 
2833  //
2834  // Pointers
2835  //
2836  RowVectorXi ptrs = RowVectorXi::Ones(nrow+1);
2837  ptrs.array() *= -1;
2838  quint32 k;
2839  for(k = 0; k < rows.size(); ++k)
2840  ptrs[rows[k]] = starts[k];
2841  ptrs[nrow] = nnzm;
2842 
2843  //
2844  // Fill in pointers for empty rows
2845  //
2846  for(k = nrow; k >= 1; --k)
2847  if(ptrs[k-1] < 0)
2848  ptrs[k-1] = ptrs[k];
2849 
2850  //
2851  for(i = 0; i < (quint32)ptrs.size(); ++i)
2852  *this << ptrs[i];
2853 
2854  //
2855  // Dimensions
2856  //
2857  qint32 dims[4];
2858  dims[0] = mat.nonZeros();
2859  dims[1] = mat.rows();
2860  dims[2] = mat.cols();
2861  dims[3] = 2;
2862 
2863  for(i = 0; i < 4; ++i)
2864  *this << dims[i];
2865 
2866  return pos;
2867 }
2868 
2869 //=============================================================================================================
2870 
2871 fiff_long_t FiffStream::write_id(fiff_int_t kind, const FiffId& id)
2872 {
2873  fiff_long_t pos = this->device()->pos();
2874 
2875  FiffId t_id = id;
2876 
2877  if(t_id.isEmpty()) {
2878  //
2879  // Create a new one
2880  //
2881  t_id = FiffId::new_file_id();
2882  }
2883 
2884  //
2885  //
2886  fiff_int_t datasize = 5*4; // The id comprises five integers
2887 
2888  *this << (qint32)kind;
2889  *this << (qint32)FIFFT_ID_STRUCT;
2890  *this << (qint32)datasize;
2891  *this << (qint32)FIFFV_NEXT_SEQ;
2892  //
2893  // Collect the bits together for one write
2894  //
2895  qint32 data[5];
2896  data[0] = t_id.version;
2897  data[1] = t_id.machid[0];
2898  data[2] = t_id.machid[1];
2899  data[3] = t_id.time.secs;
2900  data[4] = t_id.time.usecs;
2901 
2902  for(qint32 i = 0; i < 5; ++i)
2903  *this << data[i];
2904 
2905  return pos;
2906 }
2907 
2908 //=============================================================================================================
2909 
2910 fiff_long_t FiffStream::write_info_base(const FiffInfoBase & p_FiffInfoBase)
2911 {
2912  fiff_long_t pos = this->device()->pos();
2913 
2914  //
2915  // Information from the MEG file
2916  //
2917  this->start_block(FIFFB_MNE_PARENT_MEAS_FILE);
2918  this->write_string(FIFF_MNE_FILE_NAME, p_FiffInfoBase.filename);
2919  if(!p_FiffInfoBase.meas_id.isEmpty())
2920  this->write_id(FIFF_PARENT_BLOCK_ID, p_FiffInfoBase.meas_id);
2921 
2922  //
2923  // General
2924  //
2925  this->write_int(FIFF_NCHAN,&p_FiffInfoBase.nchan);
2926 
2927  //
2928  // Channel info
2929  //
2930  qint32 k;
2931  QList<FiffChInfo> chs;
2932  for(k = 0; k < p_FiffInfoBase.nchan; ++k)
2933  chs << p_FiffInfoBase.chs[k];
2934 
2935  for(k = 0; k < p_FiffInfoBase.nchan; ++k)
2936  {
2937  //
2938  // Scan numbers may have been messed up
2939  //
2940  chs[k].scanNo = k+1;//+1 because
2941  this->write_ch_info(chs[k]);
2942  }
2943 
2944  //
2945  // Blocks from the original -> skip this
2946  //
2947  bool have_hpi_result = false;
2948 
2949  //
2950  // Coordinate transformations if the HPI result block was not there
2951  //
2952  if (!have_hpi_result)
2953  {
2954  if (!p_FiffInfoBase.dev_head_t.isEmpty())
2955  this->write_coord_trans(p_FiffInfoBase.dev_head_t);
2956  if (!p_FiffInfoBase.ctf_head_t.isEmpty())
2957  this->write_coord_trans(p_FiffInfoBase.ctf_head_t);
2958  }
2959 
2960  //
2961  // Bad channels
2962  //
2963  if (p_FiffInfoBase.bads.size() > 0)
2964  {
2965  this->start_block(FIFFB_MNE_BAD_CHANNELS);
2966  this->write_name_list(FIFF_MNE_CH_NAME_LIST,p_FiffInfoBase.bads);
2967  this->end_block(FIFFB_MNE_BAD_CHANNELS);
2968  }
2969 
2970  this->end_block(FIFFB_MNE_PARENT_MEAS_FILE);
2971 
2972  return pos;
2973 }
2974 
2975 //=============================================================================================================
2976 
2977 fiff_long_t FiffStream::write_int(fiff_int_t kind, const fiff_int_t* data, fiff_int_t nel, fiff_int_t next)
2978 {
2979  fiff_long_t pos = this->device()->pos();
2980 
2981  fiff_int_t datasize = nel * 4;
2982 
2983  *this << (qint32)kind;
2984  *this << (qint32)FIFFT_INT;
2985  *this << (qint32)datasize;
2986  *this << (qint32)next;
2987 
2988  for(qint32 i = 0; i < nel; ++i)
2989  *this << data[i];
2990 
2991  return pos;
2992 }
2993 
2994 //=============================================================================================================
2995 
2996 fiff_long_t FiffStream::write_int_matrix(fiff_int_t kind, const MatrixXi& mat)
2997 {
2998  fiff_long_t pos = this->device()->pos();
2999 
3000 // qint32 FIFFT_MATRIX = 1 << 30;
3001 // qint32 FIFFT_MATRIX_INT = FIFFT_INT | FIFFT_MATRIX;
3002 
3003  qint32 numel = mat.rows() * mat.cols();
3004 
3005  fiff_int_t datasize = 4*numel + 4*3;
3006 
3007  *this << (qint32)kind;
3008  *this << (qint32)FIFFT_MATRIX_INT;
3009  *this << (qint32)datasize;
3010  *this << (qint32)FIFFV_NEXT_SEQ;
3011 
3012  qint32 i, j;
3013  // Storage order: row-major
3014  for(i = 0; i < mat.rows(); ++i)
3015  for(j = 0; j < mat.cols(); ++j)
3016  *this << mat(i,j);
3017 
3018  qint32 dims[3];
3019  dims[0] = mat.cols();
3020  dims[1] = mat.rows();
3021  dims[2] = 2;
3022 
3023  for(i = 0; i < 3; ++i)
3024  *this << dims[i];
3025 
3026  return pos;
3027 }
3028 
3029 //=============================================================================================================
3030 
3031 fiff_long_t FiffStream::write_name_list(fiff_int_t kind, const QStringList& data)
3032 {
3033  QString all = data.join(":");
3034  return this->write_string(kind,all);
3035 }
3036 
3037 //=============================================================================================================
3038 
3039 fiff_long_t FiffStream::write_named_matrix(fiff_int_t kind, const FiffNamedMatrix& mat)
3040 {
3041  fiff_long_t pos = this->device()->pos();
3042 
3043  this->start_block(FIFFB_MNE_NAMED_MATRIX);
3044  this->write_int(FIFF_MNE_NROW, &mat.nrow);
3045  this->write_int(FIFF_MNE_NCOL, &mat.ncol);
3046  if (mat.row_names.size() > 0)
3047  this->write_name_list(FIFF_MNE_ROW_NAMES, mat.row_names);
3048  if (mat.col_names.size() > 0)
3049  this->write_name_list(FIFF_MNE_COL_NAMES, mat.col_names);
3050  this->write_float_matrix(kind,mat.data.cast<float>());
3051  this->end_block(FIFFB_MNE_NAMED_MATRIX);
3052 
3053  return pos;
3054 }
3055 
3056 //=============================================================================================================
3057 
3058 fiff_long_t FiffStream::write_proj(const QList<FiffProj>& projs)
3059 {
3060  fiff_long_t pos = this->device()->pos();
3061 
3062  if (projs.size() <= 0)
3063  return -1;
3064 
3065  this->start_block(FIFFB_PROJ);
3066 
3067  for(qint32 k = 0; k < projs.size(); ++k)
3068  {
3069  this->start_block(FIFFB_PROJ_ITEM);
3070  this->write_string(FIFF_NAME,projs[k].desc);
3071  this->write_int(FIFF_PROJ_ITEM_KIND,&projs[k].kind);
3072  if (projs[k].kind == FIFFV_PROJ_ITEM_FIELD)
3073  {
3074  float fValue = 0.0f;
3075  this->write_float(FIFF_PROJ_ITEM_TIME, &fValue);
3076  }
3077 
3078  this->write_int(FIFF_NCHAN, &projs[k].data->ncol);
3079  this->write_int(FIFF_PROJ_ITEM_NVEC, &projs[k].data->nrow);
3080  qint32 bValue = (qint32)projs[k].active;
3081  this->write_int(FIFF_MNE_PROJ_ITEM_ACTIVE, &bValue);
3082  this->write_name_list(FIFF_PROJ_ITEM_CH_NAME_LIST, projs[k].data->col_names);
3083  this->write_float_matrix(FIFF_PROJ_ITEM_VECTORS, projs[k].data->data.cast<float>());//rows == length(names)
3084  this->end_block(FIFFB_PROJ_ITEM);
3085  }
3086  this->end_block(FIFFB_PROJ);
3087 
3088  return pos;
3089 }
3090 
3091 //=============================================================================================================
3092 
3093 bool FiffStream::write_raw_buffer(const MatrixXd& buf,
3094  const RowVectorXd& cals)
3095 {
3096  if (buf.rows() != cals.cols())
3097  {
3098  qWarning("buffer and calibration sizes do not match\n");
3099  return false;
3100  }
3101 
3102  typedef Eigen::Triplet<double> T;
3103  std::vector<T> tripletList;
3104  tripletList.reserve(cals.cols());
3105  for(qint32 i = 0; i < cals.cols(); ++i)
3106  tripletList.push_back(T(i, i, 1.0/cals[i]));
3107 
3108  SparseMatrix<double> inv_calsMat(cals.cols(), cals.cols());
3109  inv_calsMat.setFromTriplets(tripletList.begin(), tripletList.end());
3110 
3111  MatrixXf tmp = (inv_calsMat*buf).cast<float>();
3112  this->write_float(FIFF_DATA_BUFFER,tmp.data(),tmp.rows()*tmp.cols());
3113  return true;
3114 }
3115 
3116 //=============================================================================================================
3117 
3118 bool FiffStream::write_raw_buffer(const MatrixXd& buf,
3119  const SparseMatrix<double>& mult)
3120 {
3121  if (buf.rows() != mult.cols()) {
3122  qWarning("buffer and mult sizes do not match\n");
3123  return false;
3124  }
3125 
3126  SparseMatrix<double> inv_mult(mult.rows(), mult.cols());
3127  for (int k=0; k<inv_mult.outerSize(); ++k)
3128  for (SparseMatrix<double>::InnerIterator it(mult,k); it; ++it)
3129  inv_mult.coeffRef(it.row(),it.col()) = 1/it.value();
3130 
3131  MatrixXf tmp = (inv_mult*buf).cast<float>();
3132  this->write_float(FIFF_DATA_BUFFER,tmp.data(),tmp.rows()*tmp.cols());
3133  return true;
3134 }
3135 
3136 //=============================================================================================================
3137 
3138 bool FiffStream::write_raw_buffer(const MatrixXd& buf)
3139 {
3140  MatrixXf tmp = buf.cast<float>();
3141  this->write_float(FIFF_DATA_BUFFER,tmp.data(),tmp.rows()*tmp.cols());
3142  return true;
3143 }
3144 
3145 //=============================================================================================================
3146 
3147 fiff_long_t FiffStream::write_string(fiff_int_t kind,
3148  const QString& data)
3149 {
3150  fiff_long_t pos = this->device()->pos();
3151 
3152  fiff_int_t datasize = data.size();
3153  *this << (qint32)kind;
3154  *this << (qint32)FIFFT_STRING;
3155  *this << (qint32)datasize;
3156  *this << (qint32)FIFFV_NEXT_SEQ;
3157 
3158  this->writeRawData(data.toUtf8().constData(),datasize);
3159 
3160  return pos;
3161 }
3162 
3163 //=============================================================================================================
3164 
3165 void FiffStream::write_rt_command(fiff_int_t command, const QString& data)
3166 {
3167  fiff_int_t datasize = data.size();
3168  *this << (qint32)FIFF_MNE_RT_COMMAND;
3169  *this << (qint32)FIFFT_VOID;
3170  *this << 4+(qint32)datasize;
3171  *this << (qint32)FIFFV_NEXT_SEQ;
3172  *this << command;
3173 
3174  this->writeRawData(data.toUtf8().constData(),datasize);
3175 }
3176 
3177 //=============================================================================================================
3178 
3179 QList<FiffDirEntry::SPtr> FiffStream::make_dir(bool *ok)
3180 {
3181  FiffTag::SPtr t_pTag;
3182  QList<FiffDirEntry::SPtr> dir;
3183  FiffDirEntry::SPtr t_pFiffDirEntry;
3184  fiff_long_t pos;
3185  if(ok) *ok = false;
3186  /*
3187  * Start from the very beginning...
3188  */
3189  if(!this->device()->seek(SEEK_SET))
3190  return dir;
3191  while ((pos = this->read_tag_info(t_pTag)) != -1) {
3192  /*
3193  * Check that we haven't run into the directory
3194  */
3195  if (t_pTag->kind == FIFF_DIR)
3196  break;
3197  /*
3198  * Put in the new entry
3199  */
3200  t_pFiffDirEntry = FiffDirEntry::SPtr(new FiffDirEntry);
3201  t_pFiffDirEntry->kind = t_pTag->kind;
3202  t_pFiffDirEntry->type = t_pTag->type;
3203  t_pFiffDirEntry->size = t_pTag->size();
3204  t_pFiffDirEntry->pos = (fiff_long_t)pos;
3205 
3206  //qDebug() << "Kind: " << t_pTag->kind << "| Type:" << t_pTag->type << "| Size" << t_pTag->size() << "| Next:" << t_pTag->next;
3207 
3208  dir.append(t_pFiffDirEntry);
3209  if (t_pTag->next < 0)
3210  break;
3211  }
3212  /*
3213  * Put in the new the terminating entry
3214  */
3215  t_pFiffDirEntry = FiffDirEntry::SPtr(new FiffDirEntry);
3216  t_pFiffDirEntry->kind = -1;
3217  t_pFiffDirEntry->type = -1;
3218  t_pFiffDirEntry->size = -1;
3219  t_pFiffDirEntry->pos = -1;
3220  dir.append(t_pFiffDirEntry);
3221 
3222  if(ok) *ok = true;
3223  return dir;
3224 }
3225 
3226 //=============================================================================================================
3227 
3228 bool FiffStream::check_beginning(FiffTag::SPtr &p_pTag)
3229 {
3230  this->read_tag(p_pTag);
3231 
3232  if (p_pTag->kind != FIFF_FILE_ID)
3233  {
3234  qWarning("Fiff::open: file does not start with a file id tag\n");//consider throw
3235  return false;
3236  }
3237 
3238  if (p_pTag->type != FIFFT_ID_STRUCT)
3239  {
3240  qWarning("Fiff::open: file does not start with a file id tag\n");//consider throw
3241  return false;
3242  }
3243  if (p_pTag->size() != 20)
3244  {
3245  qWarning("Fiff::open: file does not start with a file id tag\n");//consider throw
3246  return false;
3247  }
3248  //do not rewind since the data is contained in the returned tag; -> done for TCP IP reasosn, no rewind possible there
3249  return true;
3250 }
FiffInfoBase class declaration.
#define FIFF_DIG_POINT
Definition: fiff_file.h:466
#define FIFF_PROJ_ID
Definition: fiff_file.h:577
#define FIFF_LINE_FREQ
Definition: fiff_file.h:489
QSharedDataPointer< FiffNamedMatrix > SDPtr
#define FIFF_FIRST_SAMPLE
Definition: fiff_file.h:461
FiffDirNode::SPtr make_subtree(QList< FiffDirEntry::SPtr > &dentry)
static FiffStream::SPtr open_update(QIODevice &p_IODevice)
Directory Node structure.
Definition: fiff_dir_node.h:75
QList< FiffDirEntry::SPtr > & dir()
bool read_meas_info(const FiffDirNode::SPtr &p_Node, FiffInfo &p_Info, FiffDirNode::SPtr &p_NodeInfo)
#define FIFFV_NATIVE_ENDIAN
Definition: fiff_file.h:900
FiffCoordTrans class declaration.
Eigen::Vector3f ey
Definition: fiff_ch_pos.h:114
#define FIFFB_HPI_SUBSYSTEM
Definition: fiff_file.h:384
IOUtils class declaration.
fiff_float_t range
Definition: fiff_ch_info.h:122
QList< FiffCtfComp > comps
Definition: fiff_info.h:269
QSharedPointer< FiffDirEntry > SPtr
QList< FiffProj > read_proj(const FiffDirNode::SPtr &p_Node)
FiffStream class declaration.
fiff_long_t write_name_list(fiff_int_t kind, const QStringList &data)
#define FIFF_COMMENT
Definition: fiff_file.h:459
Channel info descriptor.
Definition: fiff_ch_info.h:74
FIFF measurement file information.
Definition: fiff_info.h:84
Digitization points container and description.
QString description
Definition: fiff_info.h:262
bool read_tag(QSharedPointer< FiffTag > &p_pTag, fiff_long_t pos=-1)
static QStringList split_name_list(QString p_sNameList)
FiffCoordTrans dig_trans
Definition: fiff_info.h:267
QList< FiffDigPoint > dig
Definition: fiff_info.h:266
FiffId class declaration.
fiff_long_t write_ch_pos(const FiffChPos &chpos)
bool write_raw_buffer(const Eigen::MatrixXd &buf, const Eigen::RowVectorXd &cals)
QSharedPointer< FiffDirNode > SPtr
Definition: fiff_dir_node.h:77
Eigen::RowVectorXd cals
fiff_long_t write_float_matrix(fiff_int_t kind, const Eigen::MatrixXf &mat)
bool get_evoked_entries(const QList< FiffDirNode::SPtr > &evoked_node, QStringList &comments, QList< fiff_int_t > &aspect_kinds, QString &t)
#define FIFFV_ASPECT_STD_ERR
Definition: fiff_file.h:439
Digitization point description.
FIFF raw measurement data.
Definition: fiff_raw_data.h:78
Coordinate transformation description.
FiffId id() const
fiff_long_t write_double(fiff_int_t kind, const double *data, fiff_int_t nel=1)
fiff_long_t write_coord_trans(const FiffCoordTrans &trans)
QStringList bads
Definition: fiff_cov.h:197
fiff_long_t write_named_matrix(fiff_int_t kind, const FiffNamedMatrix &mat)
static bool copy_tree(QSharedPointer< FiffStream > &p_pStreamIn, const FiffId &in_id, const QList< QSharedPointer< FiffDirNode > > &p_Nodes, QSharedPointer< FiffStream > &p_pStreamOut)
static FiffStream::SPtr start_writing_raw(QIODevice &p_IODevice, const FiffInfo &info, Eigen::RowVectorXd &cals, Eigen::MatrixXi sel=defaultMatrixXi, bool bResetRange=true)
fiff_int_t dim
Definition: fiff_cov.h:193
Eigen::MatrixXd data
Definition: fiff_cov.h:195
#define FIFFB_MRI_SET
Definition: fiff_file.h:391
static FiffId new_file_id()
Definition: fiff_id.cpp:85
#define FIFF_MNE_CTF_COMP_CALIBRATED
#define FIFF_MNE_COV_DIAG
FIFF data tag.
Definition: fiff_tag.h:148
FiffChPos class declaration.
fiff_long_t write_dig_point(const FiffDigPoint &dig)
fiff_long_t write_tag(const QSharedPointer< FiffTag > &p_pTag, fiff_long_t pos=-1)
#define FIFF_MNE_COV_NFREE
#define FIFF_CH_INFO
Definition: fiff_file.h:456
#define FIFF_NCHAN
Definition: fiff_file.h:453
#define FIFF_MNE_COV_DIM
fiff_long_t write_info_base(const FiffInfoBase &p_FiffInfoBase)
Directory entry description.
fiff_long_t write_int_matrix(fiff_int_t kind, const Eigen::MatrixXi &mat)
#define FIFFB_PROCESSING_HISTORY
Definition: fiff_file.h:630
CTF software compensation data.
Definition: fiff_ctf_comp.h:73
#define FIFF_MNE_COV
FiffCov class declaration.
#define FIFF_MNE_CTF_COMP_KIND
Measurement channel position and coil type.
Definition: fiff_ch_pos.h:66
fiff_long_t write_float(fiff_int_t kind, const float *data, fiff_int_t nel=1)
QStringList read_bad_channels(const FiffDirNode::SPtr &p_Node)
fiff_long_t write_proj(const QList< FiffProj > &projs)
fiff_int_t nfree
Definition: fiff_cov.h:198
QList< FiffProj > projs
Definition: fiff_info.h:268
#define FIFF_MNE_PROJ_ITEM_ACTIVE
#define FIFF_PROJ_NAME
Definition: fiff_file.h:578
fiff_long_t start_block(fiff_int_t kind)
const FiffDirNode::SPtr & dirtree() const
#define FIFF_XPLOTTER_LAYOUT
Definition: fiff_file.h:840
Eigen::MatrixXd eigvec
Definition: fiff_cov.h:200
QSharedPointer< FiffTag > SPtr
Definition: fiff_tag.h:152
#define FIFF_NAME
Definition: fiff_file.h:485
Universially unique identifier.
Definition: fiff_id.h:68
fiff_long_t read_tag_info(QSharedPointer< FiffTag > &p_pTag, bool p_bDoSkip=true)
fiff_long_t write_int(fiff_int_t kind, const fiff_int_t *data, fiff_int_t nel=1, fiff_int_t next=FIFFV_NEXT_SEQ)
FiffCoordTrans dev_head_t
QString proj_name
Definition: fiff_info.h:259
FiffNamedMatrix::SDPtr data
#define FIFF_DATA_PACK
Definition: fiff_file.h:455
Eigen::Vector3f ez
Definition: fiff_ch_pos.h:115
#define FIFF_HIGHPASS
Definition: fiff_file.h:476
bool read_cov(const FiffDirNode::SPtr &p_Node, fiff_int_t cov_kind, FiffCov &p_covData)
FiffRawData class declaration.
fiffTimeRec time
Definition: fiff_id.h:154
#define FIFF_SFREQ
Definition: fiff_file.h:454
#define FIFF_MNE_FILE_NAME
fiff_int_t version
Definition: fiff_id.h:152
fiff_long_t write_cov(const FiffCov &p_FiffCov)
SSP projector data.
Definition: fiff_proj.h:75
QString acq_stim
Definition: fiff_info.h:271
FiffDirNode class declaration, which provides fiff dir tree processing methods.
Eigen::Vector3f ex
Definition: fiff_ch_pos.h:113
QList< FiffProj > projs
Definition: fiff_cov.h:196
fiff_long_t write_dir_entries(const QList< FiffDirEntry::SPtr > &dir, fiff_long_t pos=-1)
light measurement info
Eigen::Matrix< float, 4, 4, Eigen::DontAlign > invtrans
MNEMath class declaration.
#define FIFF_MNE_COV_EIGENVALUES
Eigen::MatrixXd rowcals
FiffCtfComp class declaration.
Eigen::Matrix< float, 4, 4, Eigen::DontAlign > trans
#define FIFF_MEAS_DATE
Definition: fiff_file.h:457
fiff_long_t write_ctf_comp(const QList< FiffCtfComp > &comps)
#define FIFF_ASPECT_KIND
Definition: fiff_file.h:463
#define FIFF_MNE_COV_KIND
FiffChInfo class declaration.
QString experimenter
Definition: fiff_info.h:261
#define FIFF_COORD_TRANS
Definition: fiff_file.h:475
#define FIFF_DATA_SKIP
Definition: fiff_file.h:559
fiff_int_t kind
Definition: fiff_cov.h:190
QString xplotter_layout
Definition: fiff_info.h:260
Raw Directory entry.
Definition: fiff_raw_dir.h:68
FiffStream::SPtr file
#define FIFF_DATA_BUFFER
Definition: fiff_file.h:558
FiffCoordTrans dev_ctf_t
Definition: fiff_info.h:265
fiff_int_t meas_date[2]
Definition: fiff_info.h:253
#define FIFF_MNE_CTF_COMP_DATA
#define FIFFV_ASPECT_AVERAGE
Definition: fiff_file.h:438
static FiffStream::SPtr start_file(QIODevice &p_IODevice)
static bool setup_read_raw(QIODevice &p_IODevice, FiffRawData &data, bool allow_maxshield=true, bool is_littleEndian=false)
QList< FiffRawDir > rawdir
FiffDigPoint class declaration.
QString utc_offset
Definition: fiff_info.h:263
FiffCoordTrans ctf_head_t
QSharedPointer< FiffStream > SPtr
Definition: fiff_stream.h:107
#define FIFFV_MNE_COORD_CTF_HEAD
bool isEmpty() const
Definition: fiff_id.h:175
fiff_float_t cal
Definition: fiff_ch_info.h:123
FiffStream(QIODevice *p_pIODevice)
#define FIFF_UTC_OFFSET
Definition: fiff_file.h:451
bool read_named_matrix(const FiffDirNode::SPtr &p_Node, fiff_int_t matkind, FiffNamedMatrix &mat)
fiff_float_t r[3]
fiff_long_t write_ch_info(const FiffChInfo &ch)
FiffDigitizerData class declaration.
FiffTag class declaration, which provides fiff tag I/O and processing methods.
FiffDirEntry::SPtr ent
Definition: fiff_raw_dir.h:95
void write_rt_command(fiff_int_t command, const QString &data)
static void convert_tag_data(FiffTag::SPtr tag, int from_endian, int to_endian)
Definition: fiff_tag.cpp:468
Eigen::VectorXd eig
Definition: fiff_cov.h:199
bool read_rt_tag(QSharedPointer< FiffTag > &p_pTag)
#define FIFFB_SMSH_RAW_DATA
Definition: fiff_file.h:382
#define FIFF_LOWPASS
Definition: fiff_file.h:472
Eigen::MatrixXd colcals
QList< FiffCtfComp > read_ctf_comp(const FiffDirNode::SPtr &p_Node, const QList< FiffChInfo > &p_Chs)
#define FIFF_MNE_RT_COMMAND
FiffInfo class declaration.
bool read_digitizer_data(const FiffDirNode::SPtr &p_Node, FiffDigitizerData &p_digData)
bool open(QIODevice::OpenModeFlag mode=QIODevice::ReadOnly)
fiff_long_t write_string(fiff_int_t kind, const QString &data)
fiff_int_t coil_type
Definition: fiff_ch_pos.h:111
#define FIFFV_BIG_ENDIAN
Definition: fiff_file.h:902
fiff_int_t gantry_angle
Definition: fiff_info.h:264
QStringList names
Definition: fiff_cov.h:194
fiff_long_t write_float_sparse_rcs(fiff_int_t kind, const Eigen::SparseMatrix< float > &mat)
QString acq_pars
Definition: fiff_info.h:270
fiff_long_t write_dir_pointer(fiff_int_t dirpos, fiff_long_t pos=-1, fiff_int_t next=FIFFV_NEXT_SEQ)
#define FIFF_DESCRIPTION
Definition: fiff_file.h:486
fiff_long_t end_block(fiff_int_t kind, fiff_int_t next=FIFFV_NEXT_SEQ)
fiff_long_t write_float_sparse_ccs(fiff_int_t kind, const Eigen::SparseMatrix< float > &mat)
covariance data
Definition: fiff_cov.h:77
#define FIFFV_LITTLE_ENDIAN
Definition: fiff_file.h:901
bool read_meas_info_base(const FiffDirNode::SPtr &p_Node, FiffInfoBase &p_InfoForward)
#define FIFF_GANTRY_ANGLE
Definition: fiff_file.h:557
Eigen::Vector3f r0
Definition: fiff_ch_pos.h:112
fiff_int_t machid[2]
Definition: fiff_id.h:153
#define FIFF_MNE_COORD_FRAME
bool read_tag_data(QSharedPointer< FiffTag > &p_pTag, fiff_long_t pos=-1)
#define FIFF_EXPERIMENTER
Definition: fiff_file.h:465
QList< FiffChInfo > chs
fiff_long_t write_id(fiff_int_t kind, const FiffId &id=FiffId::getDefault())