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