52#include <QCoreApplication>
85 , m_pSettings(pSettings)
100void ComputeFwd::initFwd()
108 m_listMegChs = QList<FiffChInfo>();
109 m_listEegChs = QList<FiffChInfo>();
110 m_listCompChs = QList<FiffChInfo>();
128 QTextStream *filteredStream =
nullptr;
134 qInfo(
"Source space : %s",m_pSettings->srcname.toUtf8().constData());
135 if (!(m_pSettings->transname.isEmpty()) || !(m_pSettings->mriname.isEmpty())) {
136 qInfo(
"MRI -> head transform source : %s",!(m_pSettings->mriname.isEmpty()) ? m_pSettings->mriname.toUtf8().constData() : m_pSettings->transname.toUtf8().constData());
138 qInfo(
"MRI and head coordinates are assumed to be identical.");
140 qInfo(
"Measurement data : %s",m_pSettings->measname.toUtf8().constData());
141 if (!m_pSettings->bemname.isEmpty()) {
142 qInfo(
"BEM model : %s",m_pSettings->bemname.toUtf8().constData());
144 qInfo(
"Sphere model : origin at (% 7.2f % 7.2f % 7.2f) mm",
145 1000.0f*m_pSettings->r0[
X],1000.0f*m_pSettings->r0[
Y],1000.0f*m_pSettings->r0[
Z]);
146 if (m_pSettings->include_eeg) {
148 if (m_pSettings->eeg_model_file.isEmpty()) {
149 qCritical(
"!!!!!!!!!!TODO: default_eeg_model_file();");
152 m_eegModels->fwd_list_eeg_sphere_models();
154 if (m_pSettings->eeg_model_name.isEmpty()) {
155 m_pSettings->eeg_model_name = QString(
"Default");
157 m_eegModel.reset(m_eegModels->fwd_select_eeg_sphere_model(m_pSettings->eeg_model_name));
162 if (!m_eegModel->fwd_setup_eeg_sphere_model(m_pSettings->eeg_sphere_rad,m_pSettings->use_equiv_eeg,3)) {
166 qInfo(
"Using EEG sphere model \"%s\" with scalp radius %7.1f mm",
167 m_pSettings->eeg_model_name.toUtf8().constData(),1000*m_pSettings->eeg_sphere_rad);
168 qInfo(
"%s the electrode locations to scalp",m_pSettings->scale_eeg_pos ?
"Scale" :
"Do not scale");
170 m_eegModel->scale_pos = m_pSettings->scale_eeg_pos;
171 m_eegModel->r0 = m_pSettings->r0;
174 qInfo(
"%s field computations",m_pSettings->accurate ?
"Accurate" :
"Standard");
176 qInfo(
"%s source orientations",m_pSettings->fixed_ori ?
"Fixed" :
"Free");
177 if (m_pSettings->compute_grad) {
178 qInfo(
"Compute derivatives with respect to source location coordinates");
180 qInfo(
"Destination for the solution : %s",m_pSettings->solname.toUtf8().constData());
181 if (m_pSettings->do_all) {
182 qInfo(
"Calculate solution for all source locations.");
184 if (m_pSettings->nlabel > 0) {
185 qInfo(
"Source space will be restricted to sources in %d labels",m_pSettings->nlabel);
189 qInfo(
"Reading %s...",m_pSettings->srcname.toUtf8().constData());
193 for (k = 0, m_iNSource = 0; k < static_cast<int>(m_spaces.size()); k++) {
194 if (m_pSettings->do_all) {
195 m_spaces[k]->enable_all_sources();
197 m_iNSource += m_spaces[k]->nuse;
199 if (m_iNSource == 0) {
200 qCritical(
"No sources are active in these source spaces. --all option should be used.");
203 qInfo(
"Read %d source spaces a total of %d active source locations",
static_cast<int>(m_spaces.size()),m_iNSource);
209 if (!m_pSettings->mriname.isEmpty()) {
211 if (m_mri_head_t.isEmpty()) {
215 QFile mriFile(m_pSettings->mriname);
217 if (mriStream->open()) {
218 m_mri_id.version = mriStream->id().version;
219 m_mri_id.machid[0] = mriStream->id().machid[0];
220 m_mri_id.machid[1] = mriStream->id().machid[1];
221 m_mri_id.time = mriStream->id().time;
228 if (m_mri_id.isEmpty()) {
229 qCritical(
"Couldn't read MRI file id (How come?)");
233 else if (!m_pSettings->transname.isEmpty()) {
242 m_mri_head_t.print();
246 if(!m_pSettings->pFiffInfo) {
248 QFile measname(m_pSettings->measname);
251 FIFFLIB::FiffInfo fiffInfo;
252 if(!pStream->open()) {
253 qCritical() <<
"Could not open Stream.";
257 if(!pStream->read_meas_info(pStream->dirtree(), fiffInfo, DirNode)){
258 qCritical() <<
"Could not find the channel information.";
262 m_pInfoBase = QSharedPointer<FIFFLIB::FiffInfo>(
new FiffInfo(fiffInfo));
264 m_pInfoBase = m_pSettings->pFiffInfo;
267 qCritical (
"ComputeFwd::initFwd(): no FiffInfo");
270 m_pInfoBase->mne_read_meg_comp_eeg_ch_info(m_listMegChs,
278 if (!m_pSettings->meg_head_t.isEmpty()) {
279 m_meg_head_t = m_pSettings->meg_head_t;
281 if (m_meg_head_t.isEmpty()) {
282 qCritical(
"MEG -> head coordinate transformation not found.");
286 m_iNChan = iNMeg + iNEeg;
289 qInfo(
"Read %3d MEG channels from %s",iNMeg,m_pSettings->measname.toUtf8().constData());
292 qInfo(
"Read %3d MEG compensation channels from %s",iNComp,m_pSettings->measname.toUtf8().constData());
295 qInfo(
"Read %3d EEG channels from %s",iNEeg,m_pSettings->measname.toUtf8().constData());
297 if (!m_pSettings->include_meg) {
298 qInfo(
"MEG not requested. MEG channels omitted.");
299 m_listMegChs.clear();
300 m_listCompChs.clear();
305 m_meg_head_t.print();
306 if (!m_pSettings->include_eeg) {
307 qInfo(
"EEG not requested. EEG channels omitted.");
308 m_listEegChs.clear();
318 if (m_pSettings->include_meg) {
319 m_qPath = QString(QCoreApplication::applicationDirPath() +
"/../resources/general/coilDefinitions/coil_def.dat");
320 if ( !QCoreApplication::startingUp() ) {
321 m_qPath = QCoreApplication::applicationDirPath() + QString(
"/../resources/general/coilDefinitions/coil_def.dat");
322 }
else if (!QFile::exists(m_qPath)) {
323 m_qPath =
"../resources/general/coilDefinitions/coil_def.dat";
337 if (m_compData->ncomp > 0) {
338 qInfo(
"%d compensation data sets in %s",m_compData->ncomp,m_pSettings->measname.toUtf8().constData());
340 m_listCompChs.clear();
347 FiffCoordTrans head_mri_t = m_mri_head_t.inverted();
352 m_megcoils = m_templates->create_meg_coils(m_listMegChs,
360 m_compcoils = m_templates->create_meg_coils(m_listCompChs,
375 qInfo(
"MRI coordinate coil definitions created.");
377 m_megcoils = m_templates->create_meg_coils(m_listMegChs,
386 m_compcoils = m_templates->create_meg_coils(m_listCompChs,
398 qInfo(
"Head coordinate coil definitions created.");
411 if (!m_pSettings->bemname.isEmpty()) {
413 m_pSettings->bemname = bemsolname;
415 qInfo(
"Setting up the BEM model using %s...",m_pSettings->bemname.toUtf8().constData());
416 qInfo(
"Loading surfaces...");
420 qInfo(
"Three-layer model surfaces loaded.");
427 qInfo(
"Homogeneous model surface loaded.");
429 if (iNEeg > 0 && m_bemModel->nsurf == 1) {
430 qCritical(
"Cannot use a homogeneous model in EEG calculations.");
433 qInfo(
"Loading the solution matrix...");
434 if (m_bemModel->fwd_bem_load_recompute_solution(m_pSettings->bemname.toUtf8().data(),
FWD_BEM_UNKNOWN,
false) ==
FAIL) {
438 qInfo(
"Employing the head->MRI coordinate transform with the BEM model.");
439 if (m_bemModel->fwd_bem_set_head_mri_t(m_mri_head_t) ==
FAIL) {
443 qInfo(
"BEM model %s is now set up",m_bemModel->sol_name.toUtf8().constData());
445 qInfo(
"Using the sphere model.");
450 if (m_pSettings->filter_spaces) {
451 if (!m_pSettings->mindistoutname.isEmpty()) {
452 filteredFile.setFileName(m_pSettings->mindistoutname);
453 if (!filteredFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
454 qCritical() << m_pSettings->mindistoutname;
457 filteredStream =
new QTextStream(&filteredFile);
458 qInfo(
"Omitted source space points will be output to : %s",m_pSettings->mindistoutname.toUtf8().constData());
461 m_pSettings->bemname,
464 filteredStream,m_pSettings->use_threads);
465 delete filteredStream;
466 filteredStream =
nullptr;
472void ComputeFwd::populateMetadata(MNEForwardSolution& fwd)
479 int nmeg = m_megcoils ? m_megcoils->ncoil() : 0;
480 int neeg = m_eegels ? m_eegels->ncoil() : 0;
481 fwd.
nchan = nmeg + neeg;
493 for (
int i = 0; i < static_cast<int>(m_spaces.size()); ++i) {
495 fwd.
nsource += m_spaces[i]->nuse;
510 for (
int i = 0; i < nmeg; ++i) {
511 fwd.
info.
chs.append(m_listMegChs[i]);
514 for (
int i = 0; i < neeg; ++i) {
515 fwd.
info.
chs.append(m_listEegChs[i]);
520 if (!m_pSettings->measname.isEmpty()) {
521 QFile fileBad(m_pSettings->measname);
523 if (t_pStreamBads->open()) {
524 fwd.
info.
bads = t_pStreamBads->read_bad_channels(t_pStreamBads->dirtree());
525 t_pStreamBads->close();
534 auto fwdSolution = std::make_unique<MNEForwardSolution>();
535 populateMetadata(*fwdSolution);
540 iNMeg = m_megcoils->ncoil();
543 iNEeg = m_eegels->ncoil();
546 m_pSettings->use_threads =
false;
550 if(m_spaces[0]->coord_frame != m_pSettings->coord_frame) {
558 if ((m_bemModel->compute_forward_meg(m_spaces,
562 m_pSettings->fixed_ori,
564 m_pSettings->use_threads,
565 *m_meg_forward.data(),
566 *m_meg_forward_grad.data(),
567 m_pSettings->compute_grad)) ==
FAIL) {
572 if ((m_bemModel->compute_forward_eeg(m_spaces,
574 m_pSettings->fixed_ori,
576 m_pSettings->use_threads,
577 *m_eeg_forward.data(),
578 *m_eeg_forward_grad.data(),
579 m_pSettings->compute_grad))==
FAIL) {
585 if(iNMeg > 0 && iNEeg > 0) {
586 if(m_meg_forward->data.cols() != m_eeg_forward->data.cols()) {
587 qWarning() <<
"The MEG and EEG forward solutions do not match";
590 fwdSolution->sol->clear();
591 fwdSolution->sol->nrow = m_meg_forward->nrow + m_eeg_forward->nrow;
592 fwdSolution->sol->ncol = m_meg_forward->ncol;
593 fwdSolution->sol->data = MatrixXd(fwdSolution->sol->nrow, fwdSolution->sol->ncol);
594 fwdSolution->sol->data.block(0,0,m_meg_forward->nrow,m_meg_forward->ncol) = m_meg_forward->data;
595 fwdSolution->sol->data.block(m_meg_forward->nrow,0,m_eeg_forward->nrow,m_eeg_forward->ncol) = m_eeg_forward->data;
596 fwdSolution->sol->row_names = m_meg_forward->row_names;
597 fwdSolution->sol->row_names.append(m_eeg_forward->row_names);
598 fwdSolution->sol->col_names = m_meg_forward->col_names;
599 }
else if (iNMeg > 0) {
600 fwdSolution->sol = m_meg_forward;
602 fwdSolution->sol = m_eeg_forward;
605 if(m_pSettings->compute_grad) {
606 if(iNMeg > 0 && iNEeg > 0) {
607 if(m_meg_forward_grad->data.cols() != m_eeg_forward_grad->data.cols()) {
608 qWarning() <<
"The MEG and EEG forward solutions do not match";
611 fwdSolution->sol_grad->clear();
612 fwdSolution->sol_grad->nrow = m_meg_forward_grad->nrow + m_eeg_forward_grad->nrow;
613 fwdSolution->sol_grad->ncol = m_meg_forward_grad->ncol;
614 fwdSolution->sol_grad->data = MatrixXd(fwdSolution->sol_grad->nrow, fwdSolution->sol_grad->ncol);
615 fwdSolution->sol_grad->data.block(0,0,m_meg_forward_grad->nrow,m_meg_forward_grad->ncol) = m_meg_forward_grad->data;
616 fwdSolution->sol_grad->data.block(m_meg_forward_grad->nrow,0,m_eeg_forward_grad->nrow,m_eeg_forward_grad->ncol) = m_eeg_forward_grad->data;
617 fwdSolution->sol_grad->row_names = m_meg_forward_grad->row_names;
618 fwdSolution->sol_grad->row_names.append(m_eeg_forward_grad->row_names);
619 fwdSolution->sol_grad->col_names = m_meg_forward_grad->col_names;
620 }
else if (iNMeg > 0) {
621 fwdSolution->sol_grad = m_meg_forward_grad;
623 fwdSolution->sol_grad = m_eeg_forward_grad;
636 iNMeg = m_megcoils->ncoil();
641 iNComp = m_compcoils->ncoil();
651 m_megcoils = m_templates->create_meg_coils(m_listMegChs,
659 m_compcoils = m_templates->create_meg_coils(m_listCompChs,
668 m_megcoils = m_templates->create_meg_coils(m_listMegChs,
677 m_compcoils = m_templates->create_meg_coils(m_listCompChs,
687 if(m_spaces[0]->coord_frame != m_pSettings->coord_frame) {
694 if ((m_bemModel->compute_forward_meg(m_spaces,
698 m_pSettings->fixed_ori,
700 m_pSettings->use_threads,
701 *m_meg_forward.data(),
702 *m_meg_forward_grad.data(),
703 m_pSettings->compute_grad)) ==
FAIL) {
708 m_meg_head_t = transDevHead;
712 fwd.
sol->data.block(0,0,m_meg_forward->nrow,m_meg_forward->ncol) = m_meg_forward->data;
713 if(m_pSettings->compute_grad) {
714 fwd.
sol_grad->data.block(0,0,m_meg_forward_grad->nrow,m_meg_forward_grad->ncol) = m_meg_forward_grad->data;
FiffInfo class declaration.
#define FIFFV_COORD_DEVICE
#define FIFFV_MNE_FIXED_ORI
#define FIFFV_MNE_FREE_ORI
FiffStream class declaration.
MNEForwardSolution class declaration.
ComputeFwd class declaration.
Core MNE data structures (source spaces, source estimates, hemispheres).
FIFF file I/O and data structures (raw, epochs, evoked, covariance, forward).
Forward modelling (BEM, MEG/EEG lead fields).
constexpr int FWD_COIL_ACCURACY_NORMAL
constexpr int FWD_COIL_ACCURACY_ACCURATE
constexpr int FWD_BEM_UNKNOWN
static bool checkEegLocations(const QList< FiffChInfo > &chs, int nch)
Coordinate transformation description.
FiffCoordTrans inverted() const
QSharedPointer< FiffDirNode > SPtr
Universally unique identifier.
FiffCoordTrans dev_head_t
QSharedPointer< FiffStream > SPtr
std::unique_ptr< MNELIB::MNEForwardSolution > calculateFwd()
bool updateHeadPos(const FIFFLIB::FiffCoordTrans &transDevHead, MNELIB::MNEForwardSolution &fwd)
ComputeFwd(std::shared_ptr< ComputeFwdSettings > pSettings)
static FwdBemModel::UPtr fwd_bem_load_three_layer_surfaces(const QString &name)
Load a three-layer BEM model (scalp, outer skull, inner skull) from a FIFF file.
static QString fwd_bem_make_bem_sol_name(const QString &name)
Build a standard BEM solution file name from a model name.
static FwdBemModel::UPtr fwd_bem_load_homog_surface(const QString &name)
Load a single-layer (homogeneous) BEM model from a FIFF file.
static FwdCoilSet::UPtr read_coil_defs(const QString &name)
static FwdCoilSet::UPtr create_eeg_els(const QList< FIFFLIB::FiffChInfo > &chs, int nch, const FIFFLIB::FiffCoordTrans &t=FIFFLIB::FiffCoordTrans())
static FwdEegSphereModelSet * fwd_load_eeg_sphere_models(const QString &p_sFileName, FwdEegSphereModelSet *now)
static std::unique_ptr< MNECTFCompDataSet > read(const QString &name)
FIFFLIB::fiff_int_t nsource
FIFFLIB::FiffInfoBase info
MNELIB::MNESourceSpaces src
FIFFLIB::fiff_int_t source_ori
FIFFLIB::FiffCoordTrans mri_head_t
FIFFLIB::FiffNamedMatrix::SDPtr sol_grad
FIFFLIB::fiff_int_t coord_frame
FIFFLIB::fiff_int_t nchan
FIFFLIB::FiffNamedMatrix::SDPtr sol
static int restrict_sources_to_labels(std::vector< std::unique_ptr< MNESourceSpace > > &spaces, const QStringList &labels, int nlabel)
static int filter_source_spaces(const MNESurface &surf, float limit, const FIFFLIB::FiffCoordTrans &mri_head_t, std::vector< std::unique_ptr< MNESourceSpace > > &spaces, QTextStream *filtered)
static int read_source_spaces(const QString &name, std::vector< std::unique_ptr< MNESourceSpace > > &spaces)
static int transform_source_spaces_to(int coord_frame, const FIFFLIB::FiffCoordTrans &t, std::vector< std::unique_ptr< MNESourceSpace > > &spaces)
void append(const MNESourceSpace &space)
static FiffCoordTrans combine(int from, int to, const FiffCoordTrans &t1, const FiffCoordTrans &t2)
static FiffCoordTrans identity(int from, int to)
static FiffCoordTrans readMriTransform(const QString &name)
static FiffCoordTrans readFShead2mriTransform(const QString &name)
static QString frame_name(int frame)