Ex9: FitzHugh-Nagumo

Classic FitzHugh-Nagumo oscillator — dimensionless 2-variable model

Model: FitzHugh-Nagumo

The simplest oscillatory model in NeuroML2, dimensionless:

\[\frac{dV}{dt} = \frac{V - V^3/3 - W + I}{1\,\text{s}}\] \[\frac{dW}{dt} = \frac{0.08\,(V + 0.7 - 0.8\,W)}{1\,\text{s}}\]

Parameters: \(I = 0.8\) (constant external current). Simulated for 200 s at 0.01 s step.


1. Define in TVBO

from tvbo import SimulationExperiment

exp = SimulationExperiment.from_string("""
label: "NeuroML Ex9: FitzHugh-Nagumo"
dynamics:
  name: FitzHughNagumo
  parameters:
    I: { value: 0.8 }
  state_variables:
    V:
      equation: { rhs: "V - V**3/3 - W + I" }
      initial_value: 0.0
      variable_of_interest: true
    W:
      equation: { rhs: "0.08*(V + 0.7 - 0.8*W)" }
      initial_value: 0.0
network:
  number_of_nodes: 1
integration:
  method: euler
  step_size: 0.01
  duration: 200.0
  time_scale: s
""")
print(f"Model: {exp.dynamics.name if exp.dynamics else 'network'}")
Model: FitzHughNagumo

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_Ex9__FitzHugh_Nagumo"/>

  <Include file="Cells.xml"/>
  <Include file="Networks.xml"/>
  <Include file="Simulation.xml"/>

  <!-- ════════════════════════════════════════════════════════════════
       Dynamics ComponentType & Component instances
       ════════════════════════════════════════════════════════════════ -->

  <!-- ════════════════════════════════════════════════════════════════
       ComponentType: FitzHughNagumo
       Generated from TVBO Dynamics: FitzHughNagumo
       ════════════════════════════════════════════════════════════════ -->
  <ComponentType name="FitzHughNagumo">

    <!-- Parameters -->
    <Parameter name="I" dimension="none"/>
    <!-- Coupling inputs -->
    <!-- Initial condition parameters -->
    <Parameter name="V_0" dimension="none"/>
    <Parameter name="W_0" dimension="none"/>

    <!-- Time conversion for derivatives.
         When all parameters and state variables carry proper LEMS dimensions,
         LEMS handles unit conversion natively (e.g. tau="30 ms" → 0.03 s).
         No SEC constant is needed and TimeDerivatives use the RHS directly.
         When dimensions are "none" (dimensionless models), / SEC converts
         from model time to SI seconds.
         all_dimensioned=False  needs_sec=False  time_scale=s -->
    <Constant name="SEC" dimension="time" value="1s"/>

    <!-- Exposures (one per state var

3. Run Reference

from tvbo.adapters.neuroml import run_lems_example

ref_outputs = run_lems_example("LEMS_NML2_Ex9_FN.xml")
for name, arr in ref_outputs.items():
    print(f"  {name}: shape={arr.shape}")
  ex9.dat: shape=(20001, 3)

4. Run TVBO

result = exp.run("neuroml")
da = result.integration.data
print(f"TVBO: {da.dims}, shape={da.shape}")
TVBO: ('time', 'variable'), shape=(20001, 2)

5. Compare & Plot

from tvbo.adapters.neuroml import plot_lems_comparison
plot_lems_comparison("LEMS_NML2_Ex9_FN.xml", ref_outputs, result.integration.data, title_prefix="Ex9")