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
autonomous: True; modes: 1; state variables: 2; parameters: 1.
State Equations
\[
\dot{x} = z
\]\[
\dot{z} = - x + \mu z \left(1 - x^{2}\right)
\]
State Variables
Variable
Initial Value
Equation
Flags
Description
\(x\)
0
differential (order 1)
recorded
Position
\(z\)
1
differential (order 1)
recorded
Velocity
Parameters
Parameter
Value
Description
\(\mu\)
5
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
def VanDerPol(
current_state,
t,
mu=5.0,
stimulus=False,
):
stim_t = stimulus(t) if stimulus else 0.0
# State variables
x = current_state[0]
z = current_state[1]
# Derivatives
dx_dt = z
dz_dt = -x + mu * z * (1 - x**2)
derivatives = np.array(np.broadcast_arrays(dx_dt, dz_dt))
return derivatives
# 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', vectorize=False, # Required for single-node circuits (PyRates bug))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.6384071249049157s.
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
autonomous: True; modes: 1; state variables: 2; parameters: 1.
State Equations
\[
\dot{x} = z
\]\[
\dot{z} = - x + \mu z \left(1 - x^{2}\right)
\]
State Variables
Variable
Initial Value
Equation
Flags
\(x\)
0
differential (order 1)
recorded
\(z\)
1
differential (order 1)
recorded
Parameters
Parameter
Value
\(\mu\)
5
Step 4: Run in TVBO
from tvbo import SimulationExperimentfrom IPython.display import Markdown, display# Run the loaded model in TVBOexp = SimulationExperiment( dynamics=loaded,)exp.integration.duration=100# Display experiment reportdisplay(Markdown(exp.generate_report(format="markdown")))result = exp.run().integration# Plot TVBO simulationfig, axes = plt.subplots(1, 2, figsize=(12, 4))time = result.timex = result.data.isel(variable=0).valuesz = result.data.isel(variable=1).valuesaxes[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
Local Dynamics: VanDerPol
Van der Pol oscillator - a classical nonlinear oscillator
autonomous: True; modes: 1; state variables: 2; parameters: 1.
State Equations
\[\dot{x} = z\]\[\dot{z} = - x + \mu z \left(1 - x^{2}\right)\]
INFO [tvbo.run] [+0s] STEP 1: Running simulation...
INFO [tvbo.run] [+0s] Simulation period: 100.0 ms, dt: 0.01220703125 ms
INFO [tvbo.run] [+0s] Simulation complete.
INFO [tvbo.run] [+0s] Experiment complete.
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)import model_templatesvdp_pyrates_path = os.path.join(os.path.dirname(model_templates.__file__), "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
autonomous: True; modes: 1; state variables: 2; parameters: 2.
State Equations
\[
\dot{x} = z
\]\[
\dot{z} = inp - x + \mu z \left(1 - x^{2}\right)
\]
State Variables
Variable
Initial Value
Equation
Flags
\(x\)
0
differential (order 1)
recorded
\(z\)
1
differential (order 1)
recorded
Parameters
Parameter
Value
\(\mu\)
1
\(inp\)
0
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
def vdp(
current_state,
t,
mu=2.5,
inp=0.0,
stimulus=False,
):
stim_t = stimulus(t) if stimulus else 0.0
# State variables
x = current_state[0]
z = current_state[1]
# Derivatives
dx_dt = z
dz_dt = inp - x + mu * z * (1 - x**2)
derivatives = np.array(np.broadcast_arrays(dx_dt, dz_dt))
return derivatives
Step 3: Run in TVBO
from IPython.display import Markdown, display# Run the modified model in TVBOexp = SimulationExperiment( dynamics=vdp_imported,)exp.integration.duration=100# Display experiment configurationMarkdown(exp.generate_report(format="markdown"))
Simulation Experiment
Local Dynamics: vdp
autonomous: True; modes: 1; state variables: 2; parameters: 2.
State Equations
\[\dot{x} = z\]\[\dot{z} = inp - x + \mu z \left(1 - x^{2}\right)\]
INFO [tvbo.run] [+0s] STEP 1: Running simulation...
INFO [tvbo.run] [+0s] Simulation period: 100.0 ms, dt: 0.01220703125 ms
INFO [tvbo.run] [+0s] Simulation complete.
INFO [tvbo.run] [+0s] Experiment complete.
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(dynamics=vdp_compare)exp_compare.integration.duration = Texp_compare.integration.step_size = dttvbo_result = exp_compare.run().integration# 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 vectorize=False, # Required for single-node circuits (PyRates bug))clear(pyrates_model)shutil.rmtree("_compare")# Comparetvbo_x = tvbo_result.data.isel(variable=0).valuestvbo_z = tvbo_result.data.isel(variable=1).valuesfig, 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
autonomous: True; modes: 1; state variables: 2; parameters: 1.
State Equations
\[
\dot{x} = z
\]\[
\dot{z} = - x + \mu z \left(1 - x^{2}\right)
\]
State Variables
Variable
Initial Value
Equation
Flags
\(x\)
0.5
differential (order 1)
recorded
\(z\)
0.5
differential (order 1)
recorded
Parameters
Parameter
Value
\(\mu\)
3
INFO [tvbo.run] [+0s] STEP 1: Running simulation...
INFO [tvbo.run] [+0s] Simulation period: 50.0 ms, dt: 0.001 ms
INFO [tvbo.run] [+0s] Simulation complete.
INFO [tvbo.run] [+0s] Experiment complete.
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.22346708294935524s.