Model: Izhikevich 2003
The Izhikevich (2003) model is a computationally efficient spiking neuron:
\[\frac{dv}{dt} = 0.04\,v^2 + 5\,v + 140 - U + I_{\text{ext}}\] \[\frac{dU}{dt} = a\,(b\,v - U)\]
Spike event: if \(v > \text{thresh}\) , then \(v \leftarrow c\) , \(U \leftarrow U + d\) .
Different parameter sets produce tonic (a=0.02, b=0.2, c=-65, d=6), bursting (c=-50, d=2), mixed (c=-55, d=4), and class-1 (b=-0.1, c=-55, d=6) modes.
1. Tonic Spiking
from tvbo import SimulationExperiment
exp_tonic = SimulationExperiment.from_string("""
label: "NeuroML Ex2: Izhikevich (tonic)"
dynamics:
name: IzhikevichCell
parameters:
a: { value: 0.02 }
b: { value: 0.2 }
c: { value: -65.0 }
d: { value: 6.0 }
thresh: { value: 30.0 }
I_amp: { value: 14.0 }
pulse_delay: { value: 20.0, unit: ms }
pulse_duration: { value: 2000.0, unit: ms }
derived_variables:
I_ext:
equation:
rhs: "Piecewise((I_amp, (t >= pulse_delay) & (t < pulse_delay + pulse_duration)), (0.0, True))"
state_variables:
v:
equation: { rhs: "0.04*v**2 + 5*v + 140 - U + I_ext" }
initial_value: -70.0
variable_of_interest: true
U:
equation: { rhs: "a*(b*v - U)" }
initial_value: -14.0
events:
spike:
condition: { rhs: "v > thresh" }
affect: { rhs: "v = c; U = U + d" }
network:
number_of_nodes: 1
integration:
method: euler
step_size: 0.005
duration: 200.0
time_scale: ms
""" )
print (f"Model: { exp_tonic. dynamics. name} " )
print (f"Events: { list (exp_tonic.dynamics.events.keys())} " )
Model: IzhikevichCell
Events: ['spike']
2. Bursting
exp_burst = SimulationExperiment.from_string("""
label: "NeuroML Ex2: Izhikevich (bursting)"
dynamics:
name: IzhikevichBurst
parameters:
a: { value: 0.02 }
b: { value: 0.2 }
c: { value: -50.0 }
d: { value: 2.0 }
thresh: { value: 30.0 }
I_amp: { value: 15.0 }
pulse_delay: { value: 22.0, unit: ms }
pulse_duration: { value: 2000.0, unit: ms }
derived_variables:
I_ext:
equation:
rhs: "Piecewise((I_amp, (t >= pulse_delay) & (t < pulse_delay + pulse_duration)), (0.0, True))"
state_variables:
v:
equation: { rhs: "0.04*v**2 + 5*v + 140 - U + I_ext" }
initial_value: -70.0
variable_of_interest: true
U:
equation: { rhs: "a*(b*v - U)" }
initial_value: -14.0
events:
spike:
condition: { rhs: "v > thresh" }
affect: { rhs: "v = c; U = U + d" }
network:
number_of_nodes: 1
integration:
method: euler
step_size: 0.005
duration: 200.0
time_scale: ms
""" )
3. Render LEMS XML (tonic variant)
xml = exp_tonic.render("lems" )
print (xml[:1500 ])
<Lems>
<!-- Tell jLEMS/jNeuroML which component is the simulation entry point. -->
<Target component="sim_NeuroML_Ex2__Izhikevich__tonic_"/>
<!-- ════════════════════════════════════════════════════════════════
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"
4. Run Reference (NeuroML2)
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_Ex2_Izh.xml" )
for name, arr in ref_outputs.items():
print (f" { name} : shape= { arr. shape} " )
auto.dat: shape=(40001, 10)
5. Run TVBO Versions
import numpy as np
def extract_array(exp):
da = exp.run("neuroml" ).integration.data
return np.column_stack([da.coords['time' ].values, da.values])
tvbo_tonic = extract_array(exp_tonic)
tvbo_burst = extract_array(exp_burst)
print (f"Tonic: shape= { tvbo_tonic. shape} " )
print (f"Burst: shape= { tvbo_burst. shape} " )
Tonic: shape=(40001, 3)
Burst: shape=(40001, 3)
6. Numerical Comparison
The NeuroML example outputs multiple cells (izBurst, izTonic, izMixed, izClass1). We compare the tonic variant:
from _nml_helpers import compare_traces
import numpy as np
ref_arr = list (ref_outputs.values())[0 ]
# NeuroML output: time, izBurst/v, izTonic/v, izMixed/v, izClass1/v + U columns
# We need to identify which columns are which from the file structure
print (f"Reference columns: { ref_arr. shape[1 ]} " )
# The tonic cell is typically column 2 (izTonic/v)
# Compare tonic v
ref_tonic = ref_arr[:, [0 , 2 ]] # time + izTonic/v
compare_traces(
ref_tonic, tvbo_tonic,
ref_cols= ['time' , 'v' ], tvbo_cols= ['time' , 'v' ],
)
Reference columns: 10
v: RMSE=4.284388 max_err=9.930559 corr=0.798475 ⚠️
{'v': {'rmse': np.float64(4.284388073698083),
'max_err': np.float64(9.9305587),
'corr': np.float64(0.7984746976731699),
'close': False}}
7. Plot
from _nml_helpers import plot_comparison
plot_comparison(
ref_tonic, tvbo_tonic,
ref_cols= ['time' , 'v' ], tvbo_cols= ['time' , 'v' ],
title= "Ex2: Izhikevich (tonic spiking) — NeuroML vs TVBO" ,
time_scale= 1.0 , time_unit= "s" ,
)
All Four Variants from NeuroML
import matplotlib.pyplot as plt
fig, axes = plt.subplots(4 , 1 , figsize= (10 , 10 ), sharex= True )
labels = ['Burst' , 'Tonic' , 'Mixed' , 'Class 1' ]
t_ref = ref_arr[:, 0 ]
for i in range (4 ):
axes[i].plot(t_ref, ref_arr[:, i+ 1 ], label= f'NeuroML { labels[i]} ' )
axes[i].set_ylabel('v' )
axes[i].set_title(labels[i])
axes[i].legend(loc= 'upper right' , fontsize= 8 )
axes[i].grid(True , alpha= 0.3 )
axes[- 1 ].set_xlabel("Time (s)" )
fig.suptitle("Ex2: All Izhikevich Variants (NeuroML reference)" , fontsize= 13 )
fig.tight_layout()
plt.show()