Skip to main content

MNA Library API

The mne_mna library (MNALIB namespace) implements the MNA graph-execution engine — a framework for defining, validating, serializing, and executing MEG/EEG analysis pipelines as directed acyclic graphs (DAGs). It is the runtime behind the MNA project format.

target_link_libraries(my_app PRIVATE mne_mna)

Dependencies: mne_utils, mne_fiff, mne_mne, Qt6::Core, Eigen3.

Class Inventory

Class / StructHeaderDescription
MnaProjectmna/mna_project.hTop-level project container with subjects, pipeline, and metadata
MnaSubjectmna/mna_subject.hParticipant with FreeSurfer anatomy link
MnaSessionmna/mna_session.hMeasurement session grouping recordings
MnaRecordingmna/mna_recording.hRecording run grouping file references
MnaFileRefmna/mna_file_ref.hFile reference with role, hash, and optional embedded data
MnaGraphmna/mna_graph.hComputational graph: nodes, ports, connections, validation
MnaNodemna/mna_node.hProcessing step with operator type, ports, attributes, and verification
MnaPortmna/mna_port.hTyped input/output slot on a graph node
MnaOpSchemamna/mna_op_schema.hDeclarative contract for an operation (ports, attributes, binding)
MnaOpSchemaPortmna/mna_op_schema.hPort descriptor within an operation schema
MnaOpSchemaAttrmna/mna_op_schema.hAttribute descriptor within an operation schema
MnaOpRegistrymna/mna_op_registry.hSingleton catalog of registered operation schemas and implementations
MnaRegistryLoadermna/mna_registry_loader.hLoads operator schemas from declarative JSON manifest files
MnaGraphExecutormna/mna_graph_executor.hExecutes the graph in topological order (batch, incremental, single-node)
MnaParamTreemna/mna_param_tree.hHierarchical parameter store with formula-driven bindings
MnaParamBindingmna/mna_param_binding.hDynamic parameter binding (target path → expression + trigger)
MnaVerificationmna/mna_verification.hContainer for verification checks, results, and provenance
MnaVerificationCheckmna/mna_verification.hDeclarative pre/post-condition check
MnaVerificationResultmna/mna_verification.hOutcome of evaluating a verification check
MnaScriptmna/mna_script.hInline script definition (Python, shell, R, MATLAB, Julia)
MnaIOmna/mna_io.hRead/write MNA project files (.mna JSON, .mnx CBOR)

Enumerations (mna/mna_types.h)

EnumValues
MnaFileRoleRaw, Forward, Inverse, Covariance, SourceEstimate, Bem, Surface, Annotation, Digitizer, Transform, SourceSpace, Evoked, Custom
MnaContainerFormatJson, Cbor
MnaDataKindFiffRaw, Forward, Inverse, Covariance, SourceEstimate, Epochs, Evoked, Matrix, Volume, Surface, Bem, Annotation, Label, RealTimeStream, Custom
MnaPortDirInput, Output
MnaNodeExecModeBatch, Stream, Ipc, Script

Project Model

MnaProject

Top-level container. Holds subjects, the processing pipeline, and project metadata.

#include <mna/mna_project.h>

// Create a project
MNALIB::MnaProject project;
project.name = "audvis_dspm";
project.description = "dSPM source localization";
project.mnaVersion = MnaProject::CURRENT_SCHEMA_VERSION; // "1.0"
project.created = QDateTime::currentDateTimeUtc();
MemberTypeDescription
nameQStringProject name
descriptionQStringProject description
mnaVersionQStringMNA schema version (current: "1.0")
createdQDateTimeCreation timestamp
modifiedQDateTimeLast modification timestamp
subjectsQList<MnaSubject>Subjects in the project
pipelineQList<MnaNode>Processing pipeline nodes
MethodDescription
toJson() / fromJson()JSON serialization
toCbor() / fromCbor()CBOR serialization
readFromFile(path)Read from .mna or .mnx (delegates to MnaIO)
writeToFile(path)Write to .mna or .mnx (delegates to MnaIO)

MnaSubject

MNALIB::MnaSubject subject;
subject.id = "sample";
subject.freeSurferDir = "subjects/sample";
MemberTypeDescription
idQStringSubject identifier
freeSurferDirQStringRelative path to FreeSurfer directory
sessionsQList<MnaSession>Sessions for this subject

MnaSession

MNALIB::MnaSession session;
session.id = "01";
MemberTypeDescription
idQStringSession identifier
recordingsQList<MnaRecording>Recordings in this session

MnaRecording

MNALIB::MnaRecording rec;
rec.id = "audvis";
rec.files.append(rawFileRef);
MemberTypeDescription
idQStringRecording identifier
filesQList<MnaFileRef>Files belonging to this recording

MnaFileRef

MNALIB::MnaFileRef ref;
ref.role = MnaFileRole::Raw;
ref.path = "data/sample_audvis_raw.fif";
ref.format = "fiff";
ref.sha256 = "a1b2c3...";
ref.sizeBytes = 123456;
MemberTypeDescription
roleMnaFileRoleSemantic role of the file
pathQStringRelative POSIX path from project root
sha256QStringSHA-256 hash of file contents
formatQStringFile format string (e.g., "fiff", "stc", "mgh")
sizeBytesqint64File size in bytes
embeddedboolWhether data is embedded in the MNA container
dataQByteArrayEmbedded file data (only when embedded == true)

Computational Graph

MnaGraph

The graph container manages nodes, ports, connections, and validation:

#include <mna/mna_graph.h>

MNALIB::MnaGraph graph;
graph.addNode(readRawNode);
graph.addNode(filterNode);
graph.addNode(inverseNode);

// Connect ports
graph.connect("read_raw_01", "raw",
"filter_01", "raw_input");
graph.connect("filter_01", "filtered_raw",
"inverse_01", "raw_input");

// Validate
QStringList errors;
bool valid = graph.validate(&errors);
MethodDescription
addNode(node)Add a node to the graph
removeNode(nodeId)Remove a node by ID
node(nodeId)Access a node by ID (mutable/const)
nodes()Access the full node list
hasNode(nodeId)Check if a node exists
connect(src, srcPort, dst, dstPort)Connect an output port to an input port
validate(errors)Validate acyclicity, port connections, data-kind compatibility, and schema compliance
topologicalOrder()Return nodes in execution order
toJson() / fromJson()JSON serialization
toCbor() / fromCbor()CBOR serialization
MemberTypeDescription
graphInputsQList<MnaPort>Named, typed graph-level entry points
graphOutputsQList<MnaPort>Named, typed graph-level exit points
paramTreeMnaParamTreeHierarchical parameter store

MnaNode

A single processing step in the graph:

MNALIB::MnaNode node;
node.id = "filter_01";
node.opType = "dsp.band_pass_filter";
node.attributes = {{"low_freq", 1.0}, {"high_freq", 40.0}};
node.execMode = MnaNodeExecMode::Batch;

// Add ports
MnaPort inPort;
inPort.name = "raw_input";
inPort.dataKind = MnaDataKind::FiffRaw;
inPort.direction = MnaPortDir::Input;
node.inputs.append(inPort);

MnaPort outPort;
outPort.name = "filtered_raw";
outPort.dataKind = MnaDataKind::FiffRaw;
outPort.direction = MnaPortDir::Output;
node.outputs.append(outPort);
MemberTypeDescription
idQStringUnique node identifier
opTypeQStringOperation type (looked up in MnaOpRegistry)
attributesQVariantMapOperation parameters
inputsQList<MnaPort>Input ports
outputsQList<MnaPort>Output ports
execModeMnaNodeExecModeExecution mode (Batch, Stream, Ipc, Script)
ipcCommandQStringExternal executable (for Ipc mode)
ipcArgsQStringListCommand-line arguments with {{placeholder}} tokens
ipcWorkDirQStringWorking directory for external process
ipcTransportQString"stdio", "tcp", "shm", "file"
scriptMnaScriptInline source code (for Script mode)
verificationMnaVerificationPre/post-condition checks and provenance
toolVersionQStringVersion of tool that last executed this node
executedAtQDateTimeTimestamp of last execution
dirtyboolWhether the node needs re-execution

MnaPort

MNALIB::MnaPort port;
port.name = "source_estimate";
port.dataKind = MnaDataKind::SourceEstimate;
port.direction = MnaPortDir::Output;
port.sourceNodeId = ""; // Empty for output ports
port.sourcePortName = "";
MemberTypeDescription
nameQStringPort name (unique within a node)
dataKindMnaDataKindType of data flowing through
directionMnaPortDirInput or Output
sourceNodeIdQStringUpstream node ID (input ports only)
sourcePortNameQStringUpstream output port name
streamProtocolQStringReal-time protocol: "fiff-rt", "lsl", "tcp", "shm"
streamEndpointQStringProtocol-specific address
streamBufferMsintRing-buffer length in ms (0 = unbounded)
cachedResultPathQStringPath to cached result file
cachedResultHashQStringSHA-256 for cache invalidation

Operator Schemas and Registry

MnaOpSchema

Declarative contract for an operation:

#include <mna/mna_op_schema.h>

MNALIB::MnaOpSchema schema;
schema.opType = "dsp.band_pass_filter";
schema.version = "2.2.0";
schema.binding = "internal";
schema.category = "preprocessing";
schema.description = "Apply a band-pass FIR filter";
schema.library = "mne_dsp";

MnaOpSchemaPort inPort;
inPort.name = "raw_input";
inPort.dataKind = MnaDataKind::FiffRaw;
inPort.required = true;
schema.inputPorts.append(inPort);

MnaOpSchemaAttr attr;
attr.name = "low_freq";
attr.type = QMetaType::Double;
attr.required = true;
attr.description = "Lower cutoff frequency in Hz";
schema.attributes.append(attr);
MethodDescription
validate(node, errors)Check if a node conforms to this schema

MnaOpSchemaPort

MemberTypeDescription
nameQStringPort name
dataKindMnaDataKindExpected data kind
requiredboolMust be connected?
descriptionQStringHuman-readable description

MnaOpSchemaAttr

MemberTypeDescription
nameQStringAttribute key
typeQMetaType::TypeExpected value type
requiredboolMust be set?
defaultValueQVariantDefault when not set
descriptionQStringHuman-readable description

MnaOpRegistry

Singleton catalog of all registered operations:

#include <mna/mna_op_registry.h>

auto& reg = MNALIB::MnaOpRegistry::instance();

// Register schema + implementation
reg.registerOp(schema);
reg.registerOpFunc("dsp.band_pass_filter", myFilterFunc);

// Query
QStringList allOps = reg.registeredOps();
bool exists = reg.hasOp("inv.compute_mne");
auto s = reg.schema("inv.compute_mne");
auto f = reg.opFunc("inv.compute_mne");

// Load from registry files
reg.loadRegistryFiles();
MethodDescription
instance()Access the singleton
registerOp(schema)Register an operation schema
hasOp(opType)Check if an op type is registered
schema(opType)Get the schema for an op type
registeredOps()List all registered op type strings
registerOpFunc(opType, func)Register an implementation function
opFunc(opType)Get the implementation function
loadRegistryFiles()Load registry files from resources/mna/

MnaRegistryLoader

Loads operator schemas from declarative JSON manifest files:

MethodDescription
loadFile(path, registry)Load a single manifest file
loadDirectory(dir, registry)Load master manifest + drop-in files from mna-registry.d/
saveFile(path, registry)Serialize current registry to a JSON manifest

Execution

MnaGraphExecutor

#include <mna/mna_graph_executor.h>

// Full execution
QVariantMap inputs = {{"raw_file", "/data/sample_audvis_raw.fif"}};
auto ctx = MNALIB::MnaGraphExecutor::execute(graph, inputs);

// Access results
QVariant stc = ctx.results["inverse_01::source_estimate"];

// Incremental execution (only dirty nodes)
auto ctx2 = MnaGraphExecutor::executeIncremental(graph, ctx);

// Single-node execution (for testing)
QVariantMap nodeInputs = {{"raw_input", rawData}};
QVariantMap outputs = MnaGraphExecutor::executeNode(myNode, nodeInputs);
MethodDescription
execute(graph, inputs)Execute all nodes in topological order
executeIncremental(graph, ctx)Execute only dirty nodes and dependents
executeNode(node, inputs)Execute a single node
setProgressCallback(cb)Set a per-node progress callback

Context

The execution context (MnaGraphExecutor::Context) holds:

MemberTypeDescription
resultsQMap<QString, QVariant>nodeId::portName → data
graphInputsQVariantMapGraph-level inputs populated before execution

Parameters

MnaParamTree

#include <mna/mna_param_tree.h>

MNALIB::MnaParamTree tree;
tree.setParam("filter_01/low_freq", 1.0);
tree.setParam("filter_01/high_freq", 40.0);

QVariant val = tree.param("filter_01/low_freq"); // → 1.0
bool has = tree.hasParam("filter_01/low_freq"); // → true
QStringList paths = tree.allPaths();
MethodDescription
setParam(path, value)Set a parameter value
param(path)Get a parameter value
hasParam(path)Check if a parameter exists
allPaths()List all parameter paths
addBinding(binding)Add a dynamic binding
removeBinding(targetPath)Remove a binding
bindings()List all bindings
hasBinding(targetPath)Check if a binding exists
evaluate(results)Evaluate all triggered bindings; returns changed paths
evaluateExpression(expr, results)Evaluate a single expression

MnaParamBinding

MNALIB::MnaParamBinding binding;
binding.targetPath = "inverse_01/lambda";
binding.expression = "1.0 / pow(ref('inverse_01/snr'), 2)";
binding.trigger = "on_change";
binding.dependencies = {"inverse_01/snr"};
tree.addBinding(binding);
MemberTypeDescription
targetPathQStringParameter to control: "nodeId/attrKey"
expressionQStringFormula string
triggerQString"on_change", "periodic", "manual"
periodMsintPeriod for periodic triggers (ms)
dependenciesQStringListPaths this binding reads from

Verification and Provenance

Container for verification checks, results, and provenance attached to each MnaNode.

Declarative pre- or post-condition evaluated by the executor:

MemberTypeDescription
idQStringUnique check ID within the node
descriptionQStringHuman-readable description
phaseQString"pre" or "post"
expressionQStringEvaluable expression
scriptMnaScriptOptional script for complex checks
severityQString"error", "warning", or "info"
onFailQStringRemediation hint

Outcome of evaluating a single check:

MemberTypeDescription
checkIdQStringReferences MnaVerificationCheck::id
passedboolWhether the check passed
messageQStringOutput or error message
timestampQDateTimeWhen the check was evaluated

Script Support

MnaScript

Inline code embedded in nodes (for Script exec mode) or verification checks:

MNALIB::MnaScript script;
script.language = "python";
script.interpreter = "python3";
script.code = "import mne\nraw = mne.io.read_raw_fif('{{raw_path}}')\nraw.filter(1, 40)\nraw.save('{{output_path}}')";
MemberTypeDescription
languageQString"python", "shell", "r", "matlab", "octave", "julia"
interpreterQStringInterpreter command; empty = auto-detect
interpreterArgsQStringListExtra args before the script file
codeQStringThe inline source code
sourceUriQStringOptional authoring-time reference
codeSha256QStringSHA-256 of code for integrity
keepTempFileboolPreserve temp script file after execution

File I/O

MnaIO

Read/write MNA project files. Dispatches by file extension:

#include <mna/mna_io.h>

// Read
MNALIB::MnaProject project = MNALIB::MnaIO::read("pipeline.mna");

// Write JSON
MNALIB::MnaIO::write(project, "pipeline.mna");

// Write CBOR (compact binary)
MNALIB::MnaIO::write(project, "pipeline.mnx");
MethodDescription
read(path)Read an MNA project from .mna (JSON) or .mnx (CBOR)
write(project, path)Write an MNA project to .mna or .mnx

Built-in Operations

The MNA registry ships with built-in operations covering common workflows:

NamespaceOperationDescription
ioio.read_raw_fifLoad a raw FIFF file
ioio.write_raw_fifSave a raw FIFF file
ioio.read_forwardLoad a forward solution
ioio.read_covarianceLoad a noise-covariance matrix
ioio.read_source_spaceLoad a source space
dspdsp.band_pass_filterApply a band-pass FIR filter
dspdsp.compute_covarianceCompute noise covariance from raw data
fwdfwd.make_forwardCompute forward solution
fwdfwd.make_bem_modelCompute BEM model
invinv.compute_mneCompute MNE/dSPM/sLORETA inverse
invinv.dipole_fitSequential dipole fitting

Custom operations can be registered at runtime via MnaOpRegistry::registerOp() and MnaOpRegistry::registerOpFunc().

MNE-Python Cross-Reference

MNE-CPP (MNALIB)MNE-Python Equivalent
MnaProjectNo direct equivalent (closest: mne.Report or BIDS-based project management)
MnaGraph / MnaNodeNo direct equivalent (MNE-Python uses procedural scripting)
MnaIO::read() / write()No direct equivalent
MnaOpRegistryNo direct equivalent

The MNA format is unique to MNE-CPP and fills a gap in the MNE ecosystem by providing a declarative, executable project format.

See Also