Skip to main content

ex_inverse_pwl_rap_music

Example of MNEForwardSolution and Powell Rap Music application.

Libraries: Inverse, 3D Visualization, FreeSurfer, MNE Core, FIFF I/O, Utilities

Options​

OptionDescription
--fwdPath to forward solution <file>.
--avePath to evoked <file>.
--subjDirPath to subject <directory>.
--subjSelected <subject>.
--stcOutPath to stc <file>, which is to be written.
--numDip<number> of dipole pairs to localize.
--doMovieCreate overlapping movie.
--annotTypeFsAnnotation type <type>.
--surfTypeFsSurface type <type>.

Build and run​

cmake --build build/developer-dynamic --target ex_inverse_pwl_rap_music
./out/Release/examples/ex_inverse_pwl_rap_music --help

The default inputs come from the MNE sample dataset.

Used in the API reference​

Source​

src/examples/ex_inverse_pwl_rap_music/main.cpp
//=============================================================================================================
/**
* SPDX-License-Identifier: BSD-3-Clause
* Copyright (c) 2013-2026 MNE-CPP Authors
*
* @file main.cpp
* @author Gabriel Motta <gabrielbenmotta@gmail.com>;
* Christoph Dinh <christoph.dinh@mne-cpp.org>;
* Juan GPC <jgarciaprieto@mgh.harvard.edu>;
* Lorenz Esch <lorenz.esch@tu-ilmenau.de>
* @since 0.1.0
* @date July, 2013
* @brief Example of MNEForwardSolution and Powell Rap Music application
*/

//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include <fs/fs_label.h>
#include <fs/fs_surface.h>
#include <fs/fs_surfaceset.h>
#include <fs/fs_annotationset.h>

#include <fiff/fiff_evoked.h>
#include <fiff/fiff.h>

#include <mne/mne.h>
#include <inv/inv_source_estimate.h>

#include <inv/rap_music/inv_pwl_rap_music.h>

#include <disp3D/view/brainview.h>
#include <disp3D/model/braintreemodel.h>

#include <utils/generics/mne_logger.h>

#include <iostream>

//=============================================================================================================
// QT INCLUDES
//=============================================================================================================

#include <QApplication>
#include <QCommandLineParser>
#include <QDir>
#include <QVector3D>

//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace MNELIB;
using namespace FSLIB;
using namespace FIFFLIB;
using namespace INVLIB;
using namespace UTILSLIB;
using namespace DISP3DLIB;

//=============================================================================================================
// MAIN
//=============================================================================================================

//=============================================================================================================
/**
* The function main marks the entry point of the program.
* By default, main has the storage class extern.
*
* @param[in] argc (argument count) is an integer that indicates how many arguments were entered on the command line when the program was started.
* @param[in] argv (argument vector) is an array of pointers to arrays of character objects. The array objects are null-terminated strings, representing the arguments that were entered on the command line when the program was started.
* @return the value that was set to exit() (which is 0 if exit() is called via quit()).
*/
int main(int argc, char* argv[])
{
#ifdef STATICBUILD
// Q_INIT_RESOURCE(mne_disp3d);
#endif

qInstallMessageHandler(MNELogger::customLogWriter);
QApplication app(argc, argv);

// Command Line Parser
QCommandLineParser parser;
parser.setApplicationDescription("Compute Inverse Powell RAP-MUSIC Example");
parser.addHelpOption();
QCommandLineOption fwdFileOption("fwd", "Path to forward solution <file>.", "file", QCoreApplication::applicationDirPath() + "/../resources/data/MNE-sample-data/MEG/sample/sample_audvis-meg-eeg-oct-6-fwd.fif");
QCommandLineOption evokedFileOption("ave", "Path to evoked <file>.", "file", QCoreApplication::applicationDirPath() + "/../resources/data/MNE-sample-data/MEG/sample/sample_audvis-ave.fif");
QCommandLineOption subjectDirectoryOption("subjDir", "Path to subject <directory>.", "directory", QCoreApplication::applicationDirPath() + "/../resources/data/MNE-sample-data/subjects");
QCommandLineOption subjectOption("subj", "Selected <subject>.", "subject", "sample");
QCommandLineOption stcFileOption("stcOut", "Path to stc <file>, which is to be written.", "file", ""); //"InvRapMusic.stc");
QCommandLineOption numDipolePairsOption("numDip", "<number> of dipole pairs to localize.", "number", "1");
QCommandLineOption doMovieOption("doMovie", "Create overlapping movie.", "doMovie", "false");
QCommandLineOption annotOption("annotType", "FsAnnotation type <type>.", "type", "aparc.a2009s");
QCommandLineOption surfOption("surfType", "FsSurface type <type>.", "type", "orig");

parser.addOption(fwdFileOption);
parser.addOption(evokedFileOption);
parser.addOption(subjectDirectoryOption);
parser.addOption(subjectOption);
parser.addOption(stcFileOption);
parser.addOption(numDipolePairsOption);
parser.addOption(doMovieOption);
parser.addOption(annotOption);
parser.addOption(surfOption);
parser.process(app);

// Parse command line parameters
QFile t_fileFwd(parser.value(fwdFileOption));
QFile t_fileEvoked(parser.value(evokedFileOption));
QString subject(parser.value(subjectOption));
QString subjectDir(parser.value(subjectDirectoryOption));
FsAnnotationSet t_annotationSet(subject, 2, parser.value(annotOption), subjectDir);
FsSurfaceSet t_surfSet(subject, 2, parser.value(surfOption), subjectDir);

QString t_sFileNameStc(parser.value(stcFileOption));

qint32 numDipolePairs = parser.value(numDipolePairsOption).toInt();

bool doMovie = false;
if (parser.value(doMovieOption) == "false" || parser.value(doMovieOption) == "0") {
doMovie = false;
} else if (parser.value(doMovieOption) == "true" || parser.value(doMovieOption) == "1") {
doMovie = true;
}

qDebug() << "Start calculation with stc:" << t_sFileNameStc;

// Load data
fiff_int_t setno = 0;
QPair<float, float> baseline(-1.0f, -1.0f);
FiffEvoked evoked(t_fileEvoked, setno, baseline);
if (evoked.isEmpty())
return 1;

std::cout << "evoked first " << evoked.first << "; last " << evoked.last << std::endl;

MNEForwardSolution t_Fwd(t_fileFwd);
if (t_Fwd.isEmpty())
return 1;

QStringList ch_sel_names = t_Fwd.info.ch_names;
FiffEvoked pickedEvoked = evoked.pick_channels(ch_sel_names);

//
// Cluster forward solution;
//
MNEForwardSolution t_clusteredFwd = t_Fwd.cluster_forward_solution(t_annotationSet, 20); //40);

// std::cout << "Size " << t_clusteredFwd.sol->data.rows() << " x " << t_clusteredFwd.sol->data.cols() << std::endl;
// std::cout << "Clustered Fwd:\n" << t_clusteredFwd.sol->data.row(0) << std::endl;

InvPwlRapMusic t_pwlRapMusic(t_clusteredFwd, false, numDipolePairs);

int iWinSize = 200;
if (doMovie) {
t_pwlRapMusic.setStcAttr(iWinSize, 0.6f);
}

InvSourceEstimate sourceEstimate = t_pwlRapMusic.calculateInverse(pickedEvoked);

if (doMovie) {
//Select only the activations once
MatrixXd dataPicked(sourceEstimate.data.rows(), int(std::floor(sourceEstimate.data.cols() / iWinSize)));

for (int i = 0; i < dataPicked.cols(); ++i) {
dataPicked.col(i) = sourceEstimate.data.col(i * iWinSize);
}

sourceEstimate.data = dataPicked;
}

std::cout << "source estimated" << std::endl;

if (sourceEstimate.isEmpty())
return 1;

// Write source estimate to temp files for visualization
int nVertLh = t_clusteredFwd.src[0].nuse;
InvSourceEstimate stcLh, stcRh;
stcLh.data = sourceEstimate.data.topRows(nVertLh);
stcLh.vertices = sourceEstimate.vertices.head(nVertLh);
stcLh.tmin = sourceEstimate.tmin;
stcLh.tstep = sourceEstimate.tstep;
stcLh.times = sourceEstimate.times;
stcRh.data = sourceEstimate.data.bottomRows(sourceEstimate.data.rows() - nVertLh);
stcRh.vertices = sourceEstimate.vertices.tail(sourceEstimate.vertices.size() - nVertLh);
stcRh.tmin = sourceEstimate.tmin;
stcRh.tstep = sourceEstimate.tstep;
stcRh.times = sourceEstimate.times;

QString tmpDir = QDir::tempPath();
QString lhStcPath = tmpDir + "/mnecpp_inverse_pwl_rap_music-lh.stc";
QString rhStcPath = tmpDir + "/mnecpp_inverse_pwl_rap_music-rh.stc";
QFile lhStcFile(lhStcPath);
stcLh.write(lhStcFile);
QFile rhStcFile(rhStcPath);
stcRh.write(rhStcFile);

BrainView* pBrainView = new BrainView();
BrainTreeModel* pModel = new BrainTreeModel();
pBrainView->setModel(pModel);

for (auto it = t_surfSet.data().constBegin(); it != t_surfSet.data().constEnd(); ++it) {
int hIdx = it.key();
QString hemi = (it.value().hemi() == 0) ? "lh" : "rh";
QString surfType = it.value().surf().isEmpty() ? "inflated" : it.value().surf();
pModel->addSurface(parser.value(subjectOption), hemi, surfType, it.value());
if (t_annotationSet.size() > hIdx)
pModel->addAnnotation(parser.value(subjectOption), hemi, t_annotationSet[hIdx]);
}

QObject::connect(pBrainView, &BrainView::sourceEstimateLoaded, [&](int /*nTimePoints*/) {
pBrainView->setSourceColormap("Hot");
pBrainView->setSourceThresholds(0.01f, 0.5f, 1.0f);
pBrainView->setRealtimeLooping(true);
pBrainView->setRealtimeInterval(17);
pBrainView->startRealtimeStreaming();
});
pBrainView->loadSourceEstimate(lhStcPath, rhStcPath);

if (!t_sFileNameStc.isEmpty()) {
QFile t_fileClusteredStc(t_sFileNameStc);
sourceEstimate.write(t_fileClusteredStc);
}

pBrainView->show();

return app.exec();
}