from tvbo import Dynamicsfrom IPython.display import Markdown, display# Create a Van der Pol oscillator model in TVBOvdp = Dynamics("Dynamics")vdp.name ="VanDerPol"vdp.description ="Van der Pol oscillator - a classical nonlinear oscillator"# Add parametersvdp.add_parameter("mu", value=5.0, description="Damping constant")# Add state variables with their differential equationsvdp.add_state_variable("x", equation="z", initial_value=0.0, description="Position")vdp.add_state_variable("z", equation="mu*(1 - x**2)*z - x", initial_value=1.0, description="Velocity")# Display model summary using generate_reportdisplay(Markdown(vdp.generate_report(format="markdown")))
VanDerPol
Van der Pol oscillator - a classical nonlinear oscillator
State Equations
\[
\frac{d}{d t} x = z
\]\[
\frac{d}{d t} z = - x + \mu*z*\left(1 - x^{2}\right)
\]
Parameters
Parameter
Value
Unit
Description
\(\mu\)
5.0
N/A
Damping constant
Step 2: Export to PyRates and Simulate
import osimport shutilimport matplotlib.pyplot as pltfrom pyrates import CircuitTemplate, clear
# Export TVBO model to PyRates formatos.makedirs('_pyrates_vdp', exist_ok=True)withopen('_pyrates_vdp/__init__.py', 'w') as f: f.write('')pyrates_yaml = vdp.to_yaml(format="pyrates", filepath='_pyrates_vdp/vdp.yaml')# Display exported code using render_codeprint("=== Generated Python Code ===")print(vdp.render_code(format="python"))
=== Generated Python Code ===
import numpy as np
import scipy
def VanDerPol(
current_state,
t,
mu=5.0,
local_coupling=0.0,
stimulus=None,
stimulus_scaling=1.0,
):
e = np.e
stim_t = stimulus_scaling * stimulus(t) if stimulus is not None else 0.0
x = current_state[0]
z = current_state[1]
# Derived Variables
# Time Derivatives
next_state = np.array(
[
# x
z,
# z
-x + mu * z * (1 - x**2),
]
)
return next_state
# Run in PyRatesT =100.0step_size =1e-2print("Running TVBO-exported model in PyRates...")model = CircuitTemplate.from_yaml('_pyrates_vdp.vdp.VanDerPol_circuit')results = model.run( step_size=step_size, simulation_time=T, outputs={'x': 'p/VanDerPol_op/x', 'z': 'p/VanDerPol_op/z'}, solver='scipy', method='RK45')clear(model)shutil.rmtree('_pyrates_vdp')# Plot resultsfig, axes = plt.subplots(1, 2, figsize=(12, 4))axes[0].plot(results['x'], label='x')axes[0].plot(results['z'], label='z', alpha=0.8)axes[0].set_xlabel('Time (ms)')axes[0].set_ylabel('State')axes[0].set_title('Van der Pol Oscillator (PyRates simulation)')axes[0].legend()axes[1].plot(results['x'], results['z'])axes[1].set_xlabel('x')axes[1].set_ylabel('z')axes[1].set_title('Phase Space')plt.tight_layout()plt.show()
Running TVBO-exported model in PyRates...
Compilation Progress
--------------------
(1) Translating the circuit template into a networkx graph representation...
...finished.
(2) Preprocessing edge transmission operations...
...finished.
(3) Parsing the model equations into a compute graph...
...finished.
Model compilation was finished.
Simulation Progress
-------------------
(1) Generating the network run function...
(2) Processing output variables...
...finished.
(3) Running the simulation...
...finished after 0.031563042000925634s.
Step 3: Load Back into TVBO
import tempfilefrom IPython.display import Markdown, display# Save to file and reloadwith tempfile.TemporaryDirectory() as tmpdir: filepath = os.path.join(tmpdir, "vanderpol.yaml") vdp.to_yaml(format="pyrates", filepath=filepath)# Load back into TVBO loaded = Dynamics.from_pyrates(filepath)# Display loaded model using generate_reportprint("=== Loaded Model Report ===") display(Markdown(loaded.generate_report(format="markdown")))
=== Loaded Model Report ===
VanDerPol
Van der Pol oscillator - a classical nonlinear oscillator
State Equations
\[
\frac{d}{d t} x = z
\]\[
\frac{d}{d t} z = - x + \mu*z*\left(1 - x^{2}\right)
\]
Parameters
Parameter
Value
Unit
Description
\(\mu\)
5.0
N/A
None
Step 4: Run in TVBO
from tvbo import SimulationExperimentfrom IPython.display import Markdown, display# Run the loaded model in TVBOexp = SimulationExperiment( local_dynamics=loaded,)exp.integration.duration=100# Display experiment reportdisplay(Markdown(exp.generate_report(format="markdown")))result = exp.run()# Plot TVBO simulationfig, axes = plt.subplots(1, 2, figsize=(12, 4))time = result.timex = result.data[:, 0, 0, 0]z = result.data[:, 1, 0, 0]axes[0].plot(time, x, label="x")axes[0].plot(time, z, label="z", alpha=0.8)axes[0].set_xlabel("Time (ms)")axes[0].set_ylabel("State")axes[0].set_title("Van der Pol Oscillator (TVBO simulation)")axes[0].legend()axes[1].plot(x, z)axes[1].set_xlabel("x")axes[1].set_ylabel("z")axes[1].set_title("Phase Space")plt.tight_layout()plt.show()
Simulation Experiment
Van der Pol oscillator - a classical nonlinear oscillator. The model comprises 2 state variables representing neural population activity.
\[\frac{dx}{dt} = z\]
\[\frac{dz}{dt} = - x + \mu \cdot z \cdot \left(1 - x^{2}\right)\]
Post-synaptic transformation:\[c_{\text{post}} = b + a \cdot gx\]
Parameter
Value
Description
\(b\)
0.0
Shifts the base of the connection strength while maintaining the absolute difference between different values.
\(a\)
0.00390625
Linear scaling factor of the coupled (delayed) input.
Regions: 1
Conduction velocity: 3.0 mm/ms
Method: Heun
Time step:\(\Delta t = 0.01220703125\) ms
Duration: 100 ms
Round-Trip 2: PyRates → TVBO → PyRates
Step 1: Load PyRates Model into TVBO
from tvbo import Dynamicsfrom IPython.display import Markdown, display# Load an existing PyRates model (Van der Pol oscillator from PyRates)vdp_pyrates_path ="/Users/leonmartin_bih/work_data/toolboxes/PyRates/model_templates/oscillators/vanderpol.yaml"# Load into TVBO (loads the first operator)vdp_imported = Dynamics.from_pyrates(vdp_pyrates_path)# Display using generate_reportdisplay(Markdown(vdp_imported.generate_report(format="markdown")))
vdp
State Equations
\[
\frac{d}{d t} x = z
\]\[
\frac{d}{d t} z = inp - x + \mu*z*\left(1 - x^{2}\right)
\]
Parameters
Parameter
Value
Unit
Description
\(\mu\)
1.0
N/A
None
\(inp\)
0.0
N/A
None
Step 2: Modify in TVBO and Display Code
from IPython.display import Markdown, display# Modify parameter in TVBOvdp_imported.parameters['mu'].value =2.5# Change damping# Display the generated Python code using render_codeprint("=== Generated Python Code ===")print(vdp_imported.render_code(format="python"))
=== Generated Python Code ===
import numpy as np
import scipy
def vdp(
current_state,
t,
mu=2.5,
inp=0.0,
local_coupling=0.0,
stimulus=None,
stimulus_scaling=1.0,
):
e = np.e
stim_t = stimulus_scaling * stimulus(t) if stimulus is not None else 0.0
x = current_state[0]
z = current_state[1]
# Derived Variables
# Time Derivatives
next_state = np.array(
[
# x
z,
# z
inp - x + mu * z * (1 - x**2),
]
)
return next_state
Step 3: Run in TVBO
from IPython.display import Markdown, display# Run the modified model in TVBOexp = SimulationExperiment( local_dynamics=vdp_imported,)exp.integration.duration=100# Display experiment configurationMarkdown(exp.generate_report(format="markdown"))
Simulation Experiment
The model comprises 2 state variables representing neural population activity.
\[\frac{dx}{dt} = z\]
\[\frac{dz}{dt} = inp - x + \mu \cdot z \cdot \left(1 - x^{2}\right)\]
Post-synaptic transformation:\[c_{\text{post}} = b + a \cdot gx\]
Parameter
Value
Description
\(b\)
0.0
Shifts the base of the connection strength while maintaining the absolute difference between different values.
\(a\)
0.00390625
Linear scaling factor of the coupled (delayed) input.
Regions: 1
Conduction velocity: 3.0 mm/ms
Method: Heun
Time step:\(\Delta t = 0.01220703125\) ms
Duration: 100 ms
result = exp.run()result.plot()
Step 4: Export Back to PyRates
import tempfilewith tempfile.TemporaryDirectory() as tmpdir:# Export modified model back to PyRates filepath = os.path.join(tmpdir, "vdp_modified.yaml") vdp_imported.to_yaml(format="pyrates", filepath=filepath)# Display exported YAMLprint("=== Modified model exported to PyRates YAML ===")withopen(filepath, 'r') as f:print(f.read())
Let’s verify that both engines produce identical results:
import numpy as npfrom IPython.display import Markdown, display# Define identical modelmu_value =3.0T =50.0dt =0.001# Smaller step size for better accuracy# Create TVBO modelvdp_compare = Dynamics("Dynamics")vdp_compare.name ="VdP"vdp_compare.add_parameter("mu", value=mu_value)vdp_compare.add_state_variable("x", equation="z", initial_value=0.5)vdp_compare.add_state_variable("z", equation="mu*(1 - x**2)*z - x", initial_value=0.5)# Display model reportdisplay(Markdown(vdp_compare.generate_report(format="markdown")))# Run in TVBO (uses Heun by default)exp_compare = SimulationExperiment(local_dynamics=vdp_compare)exp_compare.integration.duration = Texp_compare.integration.step_size = dttvbo_result = exp_compare.run()# Run in PyRates with same solver (heun)os.makedirs("_compare", exist_ok=True)withopen("_compare/__init__.py", "w") as f: f.write("")vdp_compare.to_yaml(format="pyrates", filepath="_compare/model.yaml")pyrates_model = CircuitTemplate.from_yaml("_compare.model.VdP_circuit")pyrates_result = pyrates_model.run( step_size=dt, simulation_time=T + dt, outputs={"x": "p/VdP_op/x", "z": "p/VdP_op/z"}, solver="heun", # Use same solver as TVBO)clear(pyrates_model)shutil.rmtree("_compare")# Comparetvbo_x = tvbo_result.data[:, 0, 0, 0]tvbo_z = tvbo_result.data[:, 1, 0, 0]fig, axes = plt.subplots(1, 2, layout='compressed')axes[0].plot(tvbo_result.time, tvbo_x, label="TVBO")axes[0].plot(pyrates_result["x"], "--", label="PyRates", alpha=0.8)axes[0].set_xlabel("Time (ms)")axes[0].set_ylabel("x")axes[0].set_title("State Variable x")axes[0].legend()axes[1].plot(tvbo_result.time, tvbo_z, label="TVBO")axes[1].plot(pyrates_result["z"], "--", label="PyRates", alpha=0.8)axes[1].set_xlabel("Time (ms)")axes[1].set_ylabel("z")axes[1].set_title("State Variable z")axes[1].legend()for ax in fig.axes: ax.set_box_aspect(1)
VdP
State Equations
\[
\frac{d}{d t} x = z
\]\[
\frac{d}{d t} z = - x + \mu*z*\left(1 - x^{2}\right)
\]
Parameters
Parameter
Value
Unit
Description
\(\mu\)
3.0
N/A
None
Compilation Progress
--------------------
(1) Translating the circuit template into a networkx graph representation...
...finished.
(2) Preprocessing edge transmission operations...
...finished.
(3) Parsing the model equations into a compute graph...
...finished.
Model compilation was finished.
Simulation Progress
-------------------
(1) Generating the network run function...
(2) Processing output variables...
...finished.
(3) Running the simulation...
...finished after 0.4788794580017566s.