51constexpr double kZero = 1e-6;
62 const QString line = in.readLine();
63 if (line.trimmed().startsWith(
'#')) {
67 while (k < line.size()) {
68 if (line[k].isSpace()) {
74 end = line.indexOf(
'"', k + 1);
75 end = end < 0 ? line.size() : end;
76 tokens << line.mid(k + 1, end - k - 1);
80 while (end < line.size() && !line[end].isSpace()) {
83 tokens << line.mid(k, end - k);
92std::unique_ptr<MNEDeriv> makeDeriv(
const QList<MNEDerivSet::Definition>& definitions,
const QString& filename,
const QString& shortname)
96 std::vector<Eigen::Triplet<float>> triplets;
98 QList<QPair<int, double>> row;
99 for (
auto it = definition.second.cbegin(); it != definition.second.cend(); ++it) {
100 if (std::fabs(it.value()) <= kZero) {
103 if (!inputs.contains(it.key())) {
106 row.append({
static_cast<int>(inputs.indexOf(it.key())), it.value()});
109 qInfo(
"MNEDerivSet - Empty derivation \"%s\" omitted", qPrintable(definition.first));
112 for (
const auto& [column, weight] : row) {
113 triplets.emplace_back(
static_cast<int>(outputs.size()), column,
static_cast<float>(weight));
115 outputs << definition.first;
117 Eigen::SparseMatrix<float> data(outputs.size(), inputs.size());
118 data.setFromTriplets(triplets.begin(), triplets.end());
119 auto deriv = std::make_unique<MNEDeriv>();
120 deriv->filename = filename;
121 deriv->shortname = shortname;
122 deriv->deriv_data = std::make_unique<MNESparseNamedMatrix>();
123 deriv->deriv_data->nrow =
static_cast<int>(outputs.size());
124 deriv->deriv_data->ncol =
static_cast<int>(inputs.size());
125 deriv->deriv_data->rowlist = outputs;
126 deriv->deriv_data->collist = inputs;
127 deriv->deriv_data->data = std::make_unique<FiffSparseMatrix>(std::move(data));
141 if (!stream->open()) {
149 qWarning(
"MNEDerivSet::read - Bad derivation data in %s", qPrintable(path));
152 auto deriv = std::make_unique<MNEDeriv>();
153 deriv->filename = path;
154 deriv->deriv_data = std::move(data);
155 set.
derivs.push_back(std::move(deriv));
166 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
167 qWarning(
"MNEDerivSet::readText - Cannot open %s", qPrintable(path));
170 QTextStream in(&file);
171 const QStringList tokens = tokenize(in);
185 Kind prev = Kind::Channel;
186 bool havePrev =
false;
188 for (
const QString& token : tokens) {
189 bool isNumber =
false;
190 const double value = token.toDouble(&isNumber);
191 const Kind kind = token ==
"=" ? Kind::Equal : token ==
"+" ? Kind::Plus
192 : token ==
"-" ? Kind::Minus
193 : token ==
"*" ? Kind::Mult
194 : isNumber ? Kind::Number
196 if (kind == Kind::Mult) {
199 if (kind == Kind::Channel && (!havePrev || prev == Kind::Channel)) {
201 }
else if (kind == Kind::Equal) {
203 qWarning(
"MNEDerivSet::readText - Misplaced equal sign in %s", qPrintable(path));
206 }
else if (kind == Kind::Channel) {
207 const double weight = prev == Kind::Minus ? -1.0 : prev == Kind::Number ? number
210 qWarning(
"MNEDerivSet::readText - Misplaced channel name in %s", qPrintable(path));
214 }
else if (kind == Kind::Number) {
215 number = prev == Kind::Minus ? -value : value;
221 qWarning(
"MNEDerivSet::readText - No derivations in %s", qPrintable(path));
226 if (set.
derivs.front()->deriv_data->nrow == 0) {
246 qWarning(
"MNEDerivSet::write - No derivations to write");
255 for (
const auto& deriv :
derivs) {
267 QList<Definition> result;
268 for (
const auto& deriv :
derivs) {
270 const Eigen::SparseMatrix<float, Eigen::RowMajor> rows = m.
data->eigen();
271 for (
int j = 0; j < m.
nrow; ++j) {
273 for (Eigen::SparseMatrix<float, Eigen::RowMajor>::InnerIterator it(rows, j); it; ++it) {
274 definition.second.insert(m.
collist.value(
static_cast<int>(it.col())), it.value());
276 result.append(definition);
286 for (
const auto& deriv : other.
derivs) {
287 derivs.push_back(std::make_unique<MNEDeriv>(*deriv));
295 std::vector<Eigen::Triplet<float>> triplets;
300 bool available =
true;
301 for (
auto it = definition.second.cbegin(); it != definition.second.cend() && available; ++it) {
302 available = std::fabs(it.value()) <= kZero || chNames.contains(it.key());
307 for (
auto it = definition.second.cbegin(); it != definition.second.cend(); ++it) {
308 if (std::fabs(it.value()) > kZero) {
309 triplets.emplace_back(
static_cast<int>(outputs.size()),
static_cast<int>(chNames.indexOf(it.key())),
static_cast<float>(it.value()));
312 outputs << definition.first;
314 if (outputs.isEmpty()) {
317 qInfo(
"MNEDerivSet::match - %lld of %d derivations were matched.",
static_cast<long long>(outputs.size()), ntot);
318 Eigen::SparseMatrix<float> data(outputs.size(), chNames.size());
319 data.setFromTriplets(triplets.begin(), triplets.end());
321 auto matched = std::make_unique<MNEDeriv>();
322 matched->shortname = QStringLiteral(
"Matched derivations");
324 matched->in_use = Eigen::VectorXi::Zero(chNames.size());
325 for (
int k = 0; k < data.outerSize(); ++k) {
326 for (Eigen::SparseMatrix<float>::InnerIterator it(data, k); it; ++it) {
327 ++matched->in_use[it.col()];
330 matched->deriv_data = std::make_unique<MNESparseNamedMatrix>();
331 matched->deriv_data->nrow =
static_cast<int>(outputs.size());
332 matched->deriv_data->ncol =
static_cast<int>(chNames.size());
333 matched->deriv_data->rowlist = outputs;
334 matched->deriv_data->collist = chNames;
335 matched->deriv_data->data = std::make_unique<FiffSparseMatrix>(std::move(data));
344 for (
const auto& deriv :
derivs) {
345 total += deriv->deriv_data ? deriv->deriv_data->nrow : 0;
Symbolic FIFF tag, block, value, unit and channel-type constants shared across FIFFLIB.
#define FIFF_MNE_DERIVATION_DATA
#define FIFFB_MNE_DERIVATIONS
#define FIFFB_MNE_NAMED_MATRIX
FIFF binary tag-stream layer: wraps a QIODevice to read and write FIFF tags, directories,...
Recursive node of the parsed FIFF block tree (FIFFB_* hierarchy with directory entries and children).
Set of channel derivations (montages): MNE-C derivation files, text definitions and matching to recor...
Core MNE data structures (source spaces, source estimates, hemispheres).
FIFF file I/O, in-memory data structures and high-level readers/writers.
std::vector< InvToken > tokenize(const InvSourceEstimate &estimate, const InvTokenizeOptions &options)
Serialise an InvSourceEstimate into a flat token sequence.
QSharedPointer< FiffDirNode > SPtr
FIFF tag-stream reader/writer: wraps a QIODevice and exposes typed read_* / write_* methods for every...
QSharedPointer< FiffStream > SPtr
static FiffStream::SPtr start_file(QIODevice &p_IODevice)
static MNEDerivSet fromDefinitions(const QList< Definition > &definitions, const QString &name=QString())
QPair< QString, QMap< QString, double > > Definition
bool write(const QString &path) const
void append(const MNEDerivSet &other)
static std::optional< MNEDerivSet > read(const QString &path)
std::vector< std::unique_ptr< MNEDeriv > > derivs
static std::optional< MNEDerivSet > readText(const QString &path)
std::unique_ptr< MNEDeriv > match(const QStringList &chNames) const
QList< Definition > definitions() const
std::unique_ptr< FIFFLIB::FiffSparseMatrix > data
static std::unique_ptr< MNESparseNamedMatrix > read(FIFFLIB::FiffStream::SPtr &stream, const FIFFLIB::FiffDirNode::SPtr &node, int kind)