MNA / MNX Project Format
The MNA (MNE Node-graph for Analysis) format is a portable project file that bundles data references, processing parameters, and an executable computational graph into a single manifest. It comes in two serialization variants:
| MNA (JSON) | MNX (Binary) | |
|---|---|---|
| Extension | .mna | .mnx |
| Encoding | UTF-8 JSON | CBOR with MNX1 magic header |
| Best for | Human reading, diffs, version control | Distribution, speed, embedded data |
| Embedded data | Base64-encoded in "data" field | Raw bytes (zero-copy CBOR) |
| Schema | Identical | Identical |
Both formats represent the exact same data model. You can convert freely between them — MnaIO::read() and MnaIO::write() dispatch by file extension.
MNA/MNX solves a fundamental problem in neuroimaging workflows: the scattering of raw data files, intermediate results, parameter choices, and processing scripts across directories with no formal link between them.
Motivation
A typical MEG/EEG analysis involves dozens of files — raw recordings, forward solutions, inverse operators, covariance matrices, source estimates — plus parameter choices (filter cutoffs, regularization values, SNR assumptions) that are often buried in scripts or lost entirely. Reproducing a result means reconstructing the exact sequence of operations and parameters, which is error-prone and labour-intensive.
MNA addresses this by capturing the complete analysis state in a single, machine-readable document:
- Data inventory — every input and output file is referenced with a path, SHA-256 hash, and semantic role
- Parameter transparency — all processing parameters are explicit, versioned, and optionally formula-driven
- Executable graph — the processing pipeline is a directed acyclic graph (DAG) that can be re-executed to reproduce results
- Provenance — each node records which tool version produced it, when it ran, and what verification checks it passed
Project Hierarchy
An MNA project follows a hierarchical data model that mirrors the structure of a neuroimaging study:
MnaProject
├── name, description, mnaVersion, created, modified
├── subjects[]
│ └── MnaSubject
│ ├── id, freeSurferDir
│ └── sessions[]
│ └── MnaSession
│ ├── id
│ └── recordings[]
│ └── MnaRecording
│ ├── id
│ └── files[]
│ └── MnaFileRef
│ ├── role (Raw, Forward, Inverse, …)
│ ├── path (relative POSIX)
│ ├── sha256
│ ├── format ("fiff", "stc", "mgh", …)
│ ├── sizeBytes
│ └── embedded (bool + data)
└── pipeline[] → MnaNode[] (the computational graph)
Class Reference
| Class | Purpose |
|---|---|
MnaProject | Top-level container. Holds subjects, the processing pipeline, and project metadata. Schema version is stored in mnaVersion (current: "1.0"). |
MnaSubject | Represents a participant. Links to a FreeSurfer SUBJECTS_DIR for anatomy. |
MnaSession | Groups recordings from one measurement session. |
MnaRecording | Groups files from one recording run (raw, events, head digitization, etc.). |
MnaFileRef | A single file reference with role, path, hash, format, and optional embedded data. |
File Roles (MnaFileRole)
| Role | Description |
|---|---|
Raw | Raw MEG/EEG recording |
Forward | Forward solution |
Inverse | Inverse operator |
Covariance | Noise or data covariance matrix |
SourceEstimate | Source-level time series (.stc, .w) |
Bem | BEM model geometry |
Surface | FreeSurfer surface mesh |
Annotation | FreeSurfer cortical parcellation |
Digitizer | Head digitization points |
Transform | Coordinate transformation (head → MRI) |
SourceSpace | Source space definition |
Evoked | Averaged evoked response |
Custom | User-defined |
Computational Graph
The heart of MNA is the computational graph: a directed acyclic graph (DAG) of processing nodes that transforms raw data into results.
MnaGraph
MnaGraph is the top-level graph container. It holds:
- A list of
MnaNodeobjects (the processing steps) - Graph-level input and output ports (
graphInputs,graphOutputs) - A hierarchical parameter tree (
MnaParamTree) - Connection and validation methods
MnaGraph graph;
graph.addNode(filterNode);
graph.addNode(inverseNode);
graph.connect("filter_01", "filtered_raw",
"inverse_01", "raw_input");
QStringList errors;
if (!graph.validate(&errors)) {
for (const auto& e : errors)
qWarning() << e;
}
MnaNode
Each node represents a single processing step:
| Field | Type | Description |
|---|---|---|
id | QString | Unique identifier (e.g., "filter_01") |
opType | QString | Operation type looked up in MnaOpRegistry (e.g., "dsp.band_pass_filter") |
attributes | QVariantMap | Operation parameters (e.g., {"low_freq": 1.0, "high_freq": 40.0}) |
inputs | QList<MnaPort> | Input ports with upstream connections |
outputs | QList<MnaPort> | Output ports |
execMode | MnaNodeExecMode | Execution mode: Batch, Stream, Ipc, or Script |
verification | MnaVerification | Pre/post-condition checks and provenance |
dirty | bool | Whether the node needs re-execution |
MnaPort
Typed input/output slot on a graph node:
| Field | Type | Description |
|---|---|---|
name | QString | Port name, unique within a node |
dataKind | MnaDataKind | Type of data flowing through (e.g., FiffRaw, Forward, SourceEstimate) |
direction | MnaPortDir | Input or Output |
sourceNodeId | QString | Upstream node (for input ports) |
sourcePortName | QString | Upstream output port name |
streamProtocol | QString | For real-time: "fiff-rt", "lsl", "tcp", "shm" |
streamEndpoint | QString | Protocol-specific address |
cachedResultPath | QString | Path to cached result file |
cachedResultHash | QString | SHA-256 hash for cache invalidation |