Simulation Experiments

Building, configuring, and running a SimulationExperiment

Overview

A SimulationExperiment is the central runnable object in TVBO. It bundles everything required to simulate a brain network model into one declarative specification:

  • dynamics — the local neural mass / population model (a Dynamics)
  • network — the brain network (connectome + parcellation + node dynamics)
  • coupling — the long-range coupling function between regions
  • integration — the numerical integrator (method, dt, duration, noise)
  • monitors / observations — derived signals (BOLD, FC, PSD, …)
  • (optional) stimulation, algorithms, optimizations, explorations, continuations — additional analysis layers

The same object can be serialized to YAML, rendered as code for several backends, executed, or exported to BIDS / openMINDS — all from a single in-memory specification that mirrors the LinkML schema.

Quick Start

from tvbo import Dynamics, SimulationExperiment

model = Dynamics.from_db("ReducedWongWangExcInh")
exp = SimulationExperiment(dynamics=model)
result = exp.run("jax", duration=10_000)
result
Experiment
└── integration
        data: (819200, 2, 1, 1)

Constructing an Experiment

From a Dynamics object

The simplest experiment is just a model. Defaults are filled in for coupling, network, integrator, and monitors:

model = Dynamics.from_db("Generic2dOscillator")
exp = SimulationExperiment(dynamics=model)

With explicit components

TVBO is declarative about where information comes from. Every component in an experiment is either:

  1. Fully specified inline — a Python instance or a dict containing all parameters, equations, etc.
  2. Loaded from YAML — see from_file / from_string.
  3. Pointed at semantically — a dict with an iri CURIE identifying the source. The IRI’s prefix selects the source (tvbo: for the built-in ontology, but also e.g. neuroml:, kg:, …); the rest of the dict is backfilled from that source.
from tvbo import SimulationExperiment
exp = SimulationExperiment(
    dynamics={"name": "ReducedWongWang", "iri": "tvbo:ReducedWongWangExcInh"},
    coupling={"name": "Linear", "iri": "tvbo:Linear"},
    network={
        "parcellation": {"iri": "tvbo:DesikanKilliany"},
        "tractogram": {"iri": "tvbo:dTOR"},
    },
    integration={"method": "Heun", "duration": 10_000, "noise": None},
)

The IRI is the load-bearing piece — a bare name string is not semantically resolvable across multiple sources. (For coupling only, a bare string is accepted as a shorthand that auto-prefixes tvbo:, but prefer the explicit iri form so the source is unambiguous.)

See Defining Networks, Coupling Functions and Integrators for the per-section details.

From the built-in database

TVBO ships a curated set of full experiment specifications — load any of them by name:

SimulationExperiment.list_db()[:10]
['AdaptiveExponentialIF_Ex8',
 'EI_Tuning_FIC_EIB_Optimization',
 'Epileptor2D_LEMS',
 'FitzHughNagumo1969_Ex9',
 'FitzHughNagumo_Ex9',
 'Generic2dOscillator_LEMS',
 'IntegrateAndFire_Ex0',
 'Izhikevich2007_Ex2',
 'JR_MEG_FrequencyGradient_Optimization',
 'JansenRit-bifurcation']
exp = SimulationExperiment.from_db("Schirner2023_MultiscaleBNM_DM")

From a YAML file

Experiments are round-trippable through YAML (see Code Generation & Export):

exp = SimulationExperiment.from_file("my_experiment.yaml")

Other constructors

Method Source
SimulationExperiment.from_db(name) built-in tvbo/database/studies/*.yaml
SimulationExperiment.from_file(path) local YAML file
SimulationExperiment.from_string(yaml) inline YAML string
SimulationExperiment.from_pyrates(path) PyRates YAML
SimulationExperiment.from_pydantic(obj) Pydantic schema instance
SimulationExperiment.from_tvb_simulator(sim) live tvb.simulator.Simulator
SimulationExperiment.from_bids(path) BIDS BEP034 derivative
SimulationExperiment.from_platform(...) TVB-O platform API
SimulationExperiment.from_openminds(src) openMINDS JSON-LD

Inspecting an Experiment

print(exp)
SimulationExperiment3
# Full parameter collection (model + coupling + integrator + network)
list(exp.parameters)[:8]
['dynamics', 'network', 'coupling']
# Symbolic representation of the right-hand side
exp.symbolic()
{'state': [Eq(Derivative(S_e(t), t), (gamma_e*H_e(t))*(1 - S_e(t)) - S_e(t)/tau_e),
  Eq(Derivative(S_i(t), t), gamma_i*H_i(t) - S_i(t)/tau_i)],
 'functions': [],
 'derived_parameters': [],
 'derived': [Eq(J_N_S_e(t), J_N*S_e(t)),
  Eq(coupling(t), (G*J_N)*(c_glob + local_coupling*S_e(t))),
  Eq(x_e(t), a_e*((-J_i*S_i(t) + (w_p*J_N_S_e(t) + (I_ext + I_o*W_e))) + coupling(t)) - b_e),
  Eq(x_i(t), a_i*(lamda*coupling(t) + ((I_o*W_i + J_N_S_e(t)) - S_i(t))) - b_i),
  Eq(H_e(t), x_e(t)/(1 - exp((-d_e)*x_e(t)))),
  Eq(H_i(t), x_i(t)/(1 - exp((-d_i)*x_i(t))))],
 'parameters': {G: 2.0,
  I_ext: 0.0,
  I_o: 0.382,
  J_N: 0.15,
  J_i: 1.0,
  W_e: 1.0,
  W_i: 0.7,
  a_e: 310.0,
  a_i: 615.0,
  b_e: 125.0,
  b_i: 177.0,
  d_e: 0.16,
  d_i: 0.087,
  gamma_e: 0.000641,
  gamma_i: 0.001,
  lamda: 0.0,
  tau_e: 100.0,
  tau_i: 10.0,
  w_p: 1.4},
 'coupling': {}}
# Round-trip through YAML
print(exp.to_yaml()[:400])
id: 3
model: ReducedWongWang
dynamics:
  name: ReducedWongWang
  iri: tvbo:ReducedWongWangExcInh
  parameters:
    G:
      name: G
      definition: Global coupling scaling
      value: 2.0
      domain:
        lo: 0.0
        hi: 10.0
        step: 0.01
        log_scale: false
      description: Global coupling scaling
    I_ext:
      name: I_ext
      definition: External stimulation paramet

Running

exp.run(format=..., **kwargs) configures delays, generates code for the requested backend, executes it, and returns an ExperimentResult:

result = exp.run("jax", duration=5_000)
print(type(result).__name__, "→", result.integration.data.shape)
ExperimentResult → (409600, 2, 87, 1)

Available backends

format= Backend Notes
"tvboptim" (default) tvboptim (JAX-based) Optimisation-friendly; supports algorithms & explorations.
"jax" / "autodiff" Pure JAX kernel Fastest forward integration, jit-compiled.
"tvb" The Virtual Brain Reference NumPy implementation.
"pyrates" PyRates Symbolic frontend, good for custom models.
"networkdynamics" NetworkDynamics.jl Julia backend (requires julia).
"mtk" ModelingToolkit.jl Symbolic Julia backend.
"bifurcation" BifurcationKit.jl / numcont Continuation analysis.

exp.run() accepts these common kwargs:

  • duration — overrides integration.duration
  • initial_conditionsTimeSeries or array; defaults from collect_initial_conditions()
  • backend-specific kwargs (e.g. jit=False for JAX)

execute() vs run()

  • exp.execute(format=...) returns the prepared simulator object (a TVB Simulator, a JIT-compiled JAX kernel, a tvboptim namespace, …). Use it when you want to drive the simulation manually.
  • exp.run(format=...) calls execute() and runs it, then wraps the output in an ExperimentResult.

Configuration & Lifecycle

Most users never need to call configure() directly — run() does it. It performs auto-fixes such as disabling delay logic when the connectome has no path lengths or conduction speed is infinite.

exp.configure()         # idempotent, called by run()
exp.collect_initial_conditions()   # build a TimeSeries of initial states
exp.collect_state()                 # snapshot of dynamics + parameters
exp.add_stimulus(stim)              # attach a Stimulus or ontology term

Inspecting Generated Code

You can render the simulator code without executing it (useful for debugging or for using the kernel outside TVBO):

print(exp.render_code("jax")[:600])


import jax
from tvbo.data.types import TimeSeries
from tvbo.utils import Bunch
import jax.numpy as jnp



def cfun(weights, history, current_state, p, delay_indices, t):
    n_node = weights.shape[0]
    b, a = p.b, p.a


    x_j = jnp.array([

    history[0, delay_indices[0].T, delay_indices[1]],
    
    ])

    S_e = x_j[0]

    pre = x_j
    pre = pre.reshape(-1, n_node ,n_node)

    def op(x): return jnp.sum(weights * x, axis=-1)
    gx = jax.vmap(op, in_axes=0)(pre)
    return b + a*gx





import jax.numpy as jnp
import jax.scipy as jsp



def dfun(current_state, t, cX, _p):
    # Par

See Code Generation & Export for the full list of supported targets.

Saving & Exporting

Goal Call
Round-trippable YAML exp.to_yaml("path.yaml")
BIDS BEP034 derivative exp.to_bids("output/derivatives/tvbo")
openMINDS JSON-LD exp.to_openminds("experiment.jsonld")
LEMS / NeuroML exp.to_lems(...)
Standalone code file exp.save_code("out/", file_name="kernel.py")
Markdown / HTML report exp.report(format="markdown")

For exporting simulation results (time series, observations, metadata) in BIDS layout, see Working with Results → BIDS Export.

See Also