Code
from tvbo import Dynamics
from tvbo.classes.experiment import SimulationExperiment
import tempfile
import osDeclarative definition of simulation outputs in TVBO
Part of the running example, where stage 2 adds an observations block that declares what to measure.
The output attribute in TVBO model specifications defines which variables are included in simulation results. This is a declarative approach that explicitly specifies what the user wants to observe from the simulation.
The output field is a list of string references to either:
# Example: Output both state and derived variables
state_variables:
x:
equation:
rhs: a * x
y:
equation:
rhs: b * y
derived_variables:
x_squared:
equation:
rhs: x**2
signal:
equation:
rhs: x + y
output:
- x # State variable (integrated)
- x_squared # Derived variable (computed post-integration)
- signal # Another derived variableDuring simulation:
x, y) are integrated using the numerical schemeThis means derived variables in output are computed outside the integration loop, from the full time series of state variables.
Let’s create and run a simple experiment to demonstrate the output format.
We’ll create a damped harmonic oscillator with both state variables and derived outputs:
yaml_content = """
name: DampedOscillator
description: "Simple damped harmonic oscillator with derived output"
parameters:
omega:
value: 1.0
description: "Natural frequency"
gamma:
value: 0.1
description: "Damping coefficient"
state_variables:
x:
description: "Position"
equation:
rhs: v
initial_value: 1.0
v:
description: "Velocity"
equation:
rhs: -omega**2 * x - gamma * v
initial_value: 0.0
derived_variables:
energy:
description: "Total energy (kinetic + potential)"
equation:
rhs: 0.5 * v**2 + 0.5 * omega**2 * x**2
output:
- x # Position (state variable)
- v # Velocity (state variable)
- energy # Total energy (derived variable)
"""
# Save to temp file and load
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
f.write(yaml_content)
temp_path = f.name
model = Dynamics.from_file(temp_path)
print(f"Model: {model.name}")
print(f"State variables: {list(model.state_variables.keys())}")
print(f"Derived variables: {list(model.derived_variables.keys())}")
print(f"Output: {model.output}")Model: DampedOscillator
State variables: ['x', 'v']
Derived variables: ['energy']
Output: ['x', 'v', 'energy']
exp = SimulationExperiment(dynamics=model)
# Run the simulation using JAX backend
res = exp.run('jax')
print(f"Result type: {type(res).__name__}")
print(f"Result shape: {res.data.shape}")
print(f"Time points: {len(res.time)}")Result type: ExperimentResult
Result shape: (81920, 3, 1, 1)
Time points: 81920
The result contains exactly what was specified in output:
output is the declarative specification - it defines exactly what appears in resultsoutput is empty, all state variables are returned (backwards compatibility)| Variable Type | In Integration? | In Output |
|---|---|---|
State variable in output |
✅ Integrated | ✅ Indexed from trace |
Derived variable in output |
❌ Not integrated | ✅ Computed from trace |
State variable NOT in output |
✅ Integrated | ❌ Not in result |