Accessing simulation output, observations, and exporting to BIDS
The ExperimentResult container: index the integration time series and observations, and export them to BIDS.
4Run
Overview
After running a simulation experiment, TVBO returns an ExperimentResult that provides structured access to all output data — raw state variables, derived observations (BOLD, FC, PSD), algorithm history, and optimization traces.
The result object mirrors the YAML experiment specification: each section of the experiment (integration, algorithms, optimizations, explorations) maps to a corresponding field on the result.
Result Architecture
ExperimentResult
├── name # Experiment label
├── source # Back-reference to SimulationExperiment
├── integration # SimulationResult — main simulation
│ ├── data # xr.DataArray, the MEASURED window (time × variable × node [× mode])
│ ├── observations # dict of observation outputs (BOLD, FC, …)
│ ├── transient # SimulationResult — the settling head, t <= 0 (if any)
│ └── full # xr.DataArray — settle and measurement, one buffer
├── algorithms # dict[str, AlgorithmResult]
│ └── fic # e.g. FIC tuning result
│ ├── state # Final tuned state
│ ├── history # Per-iteration tracking
│ ├── pre_tuning # SimulationResult before algorithm
│ └── post_tuning # SimulationResult after algorithm
├── optimizations # dict[str, OptimizationResult]
│ └── loss_fc # e.g. FC-based optimization
│ ├── state # Fitted parameters
│ ├── history # Loss trajectory
│ └── simulation # SimulationResult with fitted params
├── explorations # dict[str, ExplorationResult]
│ └── grid # Parameter sweep results
└── continuations # dict — bifurcation analysis results
When running experiments with algorithms (e.g. FIC, EIB), results track the full iteration history:
# Load and run an experiment with algorithmsexp = SimulationExperiment.from_db("EI_Tuning_FIC_EIB_Optimization")result = exp.run("tvboptim")fic = result.algorithms['fic']fic.name # 'fic'fic.n_iterations # 200fic.state # Final tuned state (parameter arrays)fic.history # Per-iteration trackingfic.pre_tuning # SimulationResult before tuningfic.post_tuning # SimulationResult after tuningfic.convergence # Computed convergence metrics
Optimization Results
Optimization results track loss trajectory and parameter evolution:
opt = result.optimizations['gradient_eib']opt.name # 'gradient_eib'opt.n_steps # Number of gradient stepsopt.final_loss # Final loss valueopt.loss_trajectory # Loss at each step (array)opt.state # Fitted parametersopt.simulation # Post-optimization SimulationResult
Exporting Results
BIDS-Compatible Export
ExperimentResult.export() writes simulation data and experiment metadata to a BIDS-compatible directory following BEP034 conventions (computational model derivatives):
output_dir/
├── dataset_description.json
└── sub-{subject}/
├── sub-{subject}_desc-{desc}_experiment.yaml # full LinkML experiment spec
└── ts/
├── sub-{subject}_desc-{desc}_ts-sim_State.nc # raw state variables
├── sub-{subject}_desc-{desc}_ts-sim_State.json # sidecar metadata
└── sub-{subject}_desc-{desc}_ts-{obs}.nc # one per observation
# Show what was writtenfor root, dirs, files in os.walk(outdir): level = root.replace(outdir, "").count(os.sep) indent =" "* levelprint(f"{indent}{os.path.basename(root)}/")for f insorted(files):print(f" {indent}{f}")
Simulation data is stored as netCDF4 (.nc) — a self-describing scientific data format built on HDF5. Each file contains the full array with named dimensions and coordinates, readable by any netCDF or HDF5 tool.
Why netCDF and not NIfTI or plain HDF5?
Format
Suitable?
Reason
NIfTI
No
Designed for volumetric (voxel) imaging. Region-by-region time series (time × variable × node × mode) don’t fit the NIfTI data model and we’d lose labelled axes.
Plain HDF5
Partially
HDF5 has no built-in concept of named dimensions or coordinate variables; we’d need to invent our own conventions.
netCDF4 files are HDF5 files. Any HDF5 reader (h5py, HDFView, MATLAB’s h5read) can open them directly. The netCDF layer just adds self-describing dimension names and coordinates on top.
Reading exported data back
import xarray as xrnc_files = [f for f in os.listdir(os.path.join(outdir, "sub-01", "ts")) if f.endswith(".nc")]nc_path = os.path.join(outdir, "sub-01", "ts", nc_files[0])ds = xr.open_dataset(nc_path)ds['data']