Model: AdEx (adExIaFCell)
The Adaptive Exponential Integrate-and-Fire model Brette2005?:
\[C\frac{dv}{dt} = -g_L(v - E_L) + g_L \Delta_T \exp\!\left(\frac{v - V_T}{\Delta_T}\right) - w + I_{\text{ext}}\] \[\tau_w\frac{dw}{dt} = a(v - E_L) - w\]
Spike event: if \(v > \text{thresh}\), then \(v \leftarrow \text{reset}\), \(w \leftarrow w + b\).
The NeuroML example includes four variants (burst2, burst4, burstChaos, rebound).
1. Define in TVBO (bursting variant)
from tvbo import SimulationExperiment
exp = SimulationExperiment.from_string("""
label: "NeuroML Ex8: AdEx (bursting)"
dynamics:
name: AdaptiveExponentialIF
parameters:
C: { value: 281.0, description: "Capacitance (pF)" }
gL: { value: 30.0, description: "Leak conductance (nS)" }
EL: { value: -70.6, description: "Leak reversal (mV)" }
VT: { value: -50.4 }
thresh: { value: -40.4 }
reset: { value: -48.5 }
delT: { value: 2.0 }
tauw: { value: 40.0 }
a: { value: 4.0, description: "Subthreshold adaptation (nS)" }
b: { value: 80.0, description: "Spike-triggered adaptation (pA, = 0.08 nA)" }
refract: { value: 0.0, unit: ms, description: "Refractory period" }
derived_variables:
I_ext:
equation:
rhs: "800.0"
description: "Constant current 0.8 nA = 800 pA (pulseGen1: delay=0, duration=2000ms)"
state_variables:
v:
equation:
rhs: "(-gL*(v - EL) + gL*delT*exp((v - VT)/delT) - w + I_ext) / C"
initial_value: -70.6
variable_of_interest: true
w:
equation:
rhs: "(a*(v - EL) - w) / tauw"
initial_value: 0.0
events:
spike:
condition: { rhs: "v > thresh" }
affect: { rhs: "v = reset; w = w + b" }
network:
number_of_nodes: 1
integration:
method: euler
step_size: 0.025
duration: 300.0
time_scale: ms
""")
print(f"Model: {exp.dynamics.name}, SVs: {list(exp.dynamics.state_variables.keys())}")
Model: AdaptiveExponentialIF, SVs: ['v', 'w']
2. Render LEMS XML
xml = exp.render("lems")
print(xml[:1500])
<Lems>
<!-- Tell jLEMS/jNeuroML which component is the simulation entry point. -->
<Target component="sim_NeuroML_Ex8__AdEx__bursting_"/>
<!-- ════════════════════════════════════════════════════════════════
Dimensions & Units (inline — no external includes needed)
════════════════════════════════════════════════════════════════ -->
<!-- Dimensions -->
<Dimension name="none"/>
<Dimension name="time" t="1"/>
<Dimension name="voltage" m="1" l="2" t="-3" i="-1"/>
<Dimension name="per_time" t="-1"/>
<Dimension name="conductance" m="-1" l="-2" t="3" i="2"/>
<Dimension name="capacitance" m="-1" l="-2" t="4" i="2"/>
<Dimension name="current" i="1"/>
<Dimension name="resistance" m="1" l="2" t="-3" i="-2"/>
<Dimension name="concentration" l="-3" n="1"/>
<Dimension name="substance" n="1"/>
<Dimension name="charge" t="1" i="1"/>
<Dimension name="temperature" k="1"/>
<!-- Units -->
<Unit symbol="s" dimension="time" power="0"/>
<Unit symbol="ms" dimension="time" power="-3"/>
<Unit symbol="us" dimension="time" power="-6"/>
<Unit symbol="V" dimension="voltage" power="0"/>
<Unit symbol="mV" dimension="voltage" power="-3"/>
<Unit symbol="A" dimension="current" power="0"/>
<Unit symbol="mA" dimension="current" power="-3"/>
<Unit symbol="nA" dimension="current" power="-9"/>
<Unit symbol="pA" dimension="current" power="-12"/>
<Unit symbol="S" dimension="conductance" power="0"/>
<Unit symbol="mS" dimension="conductance" po
3. Run Reference
import sys, os
sys.path.insert(0, os.path.dirname(os.path.abspath(".")))
from _nml_helpers import run_lems_example
ref_outputs = run_lems_example("LEMS_NML2_Ex8_AdEx.xml")
for name, arr in ref_outputs.items():
print(f" {name}: shape={arr.shape}")
adEx_2burst.dat: shape=(12001, 3)
adEx_4burst.dat: shape=(12001, 3)
adEx_chaos.dat: shape=(12001, 3)
adEx_rebound.dat: shape=(12001, 3)
4. Run TVBO
import numpy as np
result = exp.run("neuroml")
da = result.integration.data
tvbo_arr = np.column_stack([da.coords['time'].values, da.values])
print(f"TVBO: shape={tvbo_arr.shape}")
5. Comparison
The NeuroML example has 4 cells. We compare the burst2 variant (first column):
from _nml_helpers import compare_traces, plot_comparison
import numpy as np
ref_arr = list(ref_outputs.values())[0]
# First data column should be adExBurst2/v
ref_v = ref_arr[:, [0, 1]]
tvbo_v = tvbo_arr[:, [0, 1]]
compare_traces(ref_v, tvbo_v, ref_cols=['time', 'v'], tvbo_cols=['time', 'v'])
plot_comparison(
ref_v, tvbo_v,
ref_cols=['time', 'v'], tvbo_cols=['time', 'v'],
title="Ex8: AdEx (bursting) — NeuroML vs TVBO",
)
v: RMSE=48.553404 max_err=70.529400 corr=1.000000 ⚠️
All AdEx Variants (NeuroML reference)
import matplotlib.pyplot as plt
fig, axes = plt.subplots(4, 1, figsize=(10, 10), sharex=True)
labels = ['Burst2', 'Burst4', 'BurstChaos', 'Rebound']
t_ref = ref_arr[:, 0] * 1000 # ms
for i in range(min(4, ref_arr.shape[1]-1)):
axes[i].plot(t_ref, ref_arr[:, i+1] * 1000, color='C0')
axes[i].set_ylabel('v (mV)')
axes[i].set_title(labels[i] if i < len(labels) else f'col {i+1}')
axes[i].grid(True, alpha=0.3)
axes[-1].set_xlabel("Time (ms)")
fig.suptitle("Ex8: All AdEx Variants (NeuroML reference)", fontsize=13)
fig.tight_layout()
plt.show()