Ex6: NMDA Synapse

Cell with morphology receiving NMDA synapse input and DC current

Model: NMDA Synapse

A passive cell (with morphology and biophysics) receives NMDA synapse input from a spike generator, plus a DC current injection. Demonstrates the cell type with channelDensity and blockingPlasticSynapse with Mg²⁺ block.

Reference: NeuroML2 LEMS_NML2_Ex6_NMDA.xml


1. Define Network in TVBO

from tvbo import SimulationExperiment

exp = SimulationExperiment.from_string("""
label: "NeuroML Ex6: NMDA Synapse"
network:
  dynamics:
    passiveCell:
      name: passiveCell
      iri: neuroml:cell
      parameters:
        diameter: {value: 17.841242}
        specificCapacitance: {value: 1.0, unit: uF_per_cm2}
        initMembPotential: {value: -65, unit: mV}
        spikeThresh: {value: -20, unit: mV}
        resistivity: {value: 0.03, unit: kohm_cm}
      components:
        passiveChan:
          name: passiveChan
          iri: neuroml:ionChannelHH
          parameters:
            conductance: {value: 10, unit: pS}
            condDensity: {value: 0.0003, unit: S_per_cm2}
            erev: {value: -54.3, unit: mV}
            ion: {description: non_specific}
    spikeGen75ms:
      name: spikeGen75ms
      iri: neuroml:spikeGenerator
      parameters:
        period: {value: 75, unit: ms}
    nmdaSyn1:
      name: nmdaSyn1
      iri: neuroml:blockingPlasticSynapse
      parameters:
        gbase: {value: 0.5, unit: nS}
        erev: {value: 0, unit: mV}
        tauRise: {value: 2, unit: ms}
        tauDecay: {value: 8, unit: ms}
      modes:
        blockMechanism:
          name: blockMechanism
          iri: neuroml:voltageConcDepBlockMechanism
          parameters:
            species: {description: mg}
            blockConcentration: {value: 1.2, unit: mM}
            scalingConc: {value: 1.920544, unit: mM}
            scalingVolt: {value: 16.129, unit: mV}
    pulseGen2:
      name: pulseGen2
      iri: neuroml:pulseGenerator
      parameters:
        delay: {value: 200, unit: ms}
        duration: {value: 10000, unit: ms}
        amplitude: {value: 0.065, unit: nA}
  nodes:
    - {id: 0, dynamics: passiveCell}
    - {id: 10, dynamics: spikeGen75ms}
    - {id: 100, dynamics: pulseGen2}
  edges:
    - {source: 10, target: 0, coupling: nmdaSyn1}
    - {source: 100, target: 0}
integration:
  method: euler
  step_size: 0.01
  duration: 400.0
  time_scale: ms
""")
print(f"TVBO model: {exp.dynamics.name if exp.dynamics else "network"}")
TVBO model: network

2. Render LEMS XML

xml = exp.render("lems")
print(xml[:3000])
<Lems>

  <!-- Tell jLEMS/jNeuroML which component is the simulation entry point. -->
  <Target component="sim_NeuroML_Ex6__NMDA_Synapse"/>

  <!-- ════════════════════════════════════════════════════════════════
       Standard NeuroML2 type includes for network mode.
       Provides all standard dimensions, units, synapse types, input
       types, network infrastructure, and simulation types.
       ════════════════════════════════════════════════════════════════ -->
  <Include file="Cells.xml"/>
  <Include file="Networks.xml"/>
  <Include file="Simulation.xml"/>

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


  <!-- ── ComponentType: passiveCell ── -->
  <ComponentType name="passiveCell" extends="baseCellMembPot">
    <Parameter name="diameter" dimension="none"/>
    <Parameter name="initMembPotential" dimension="voltage"/>
    <Parameter name="resistivity" dimension="none"/>
    <Parameter name="specificCapacitance" dimension="none"/>
    <Parameter name="spikeThresh" dimension="voltage"/>
    <Constant name="SEC" dimension="time" value="1ms"/>
    <!-- Dynamically attached synapses/inputs from network connections -->
    <Attachments name="synapses" type="basePointCurrent"/>

    <Dynamics>
      <!-- ── Flat dynamics ── -->
      <OnStart>
      </OnStart>
    </Dynamics>
  </ComponentType>

  <Component id="passiveCell_inst" type="passiveCell" diameter="17.841242" initMembPotential="-65 mV" resistivity="0.03" specificCapacitance="1.0" spikeThresh="-20 mV"/>


  <!-- ════════════════════════════════════════════════════════════════
       Built-in/named synapse definitions (no custom ODE dynamics)
       ════════════════════════════════════════════════════════════════ -->
  <!-- Synapse: nmdaSyn1 (nmdaSyn1) -->
  <nmdaSyn1 id="nmdaSyn1"/>

  <!-- ════════════════════════════════════════════════════════════════
       Input Sources (pulseGenerator, spikeGenerator, spikeArray, etc.)
       ════════════════════════════════════════════════════════════════ -->
  <pulseGenerator id="pulseGen2" amplitude="0.065 nA" delay="200 ms" duration="10000 ms"/>
  <spikeGenerator id="spikeGen75ms" period="75 ms"/>

  <!-- ════════════════════════════════════════════════════════════════
       Network
       ════════════════════════════════════════════════════════════════ -->
  <network id="net1">
    <population id="passiveCell_pop" component="passiveCell_inst" size="1"/>
    <population id="spikeGen75ms_pop" component="spikeGen75ms" size="1"/>

    <synapticConnection from="spikeGen75ms_pop[0]" to="passiveCell_pop[0]" synapse="nmdaSyn1" destination="synapses"/>

    <explicitInput target="passiveCell_pop[0]" input="pulseGen2" destination="synapses"/>
  </network>

  <!-- ════════════════════════════════════════════════════════════════
       Simulation — target the network
       ═════════════════════════

3. Run Reference

from tvbo.adapters.neuroml import run_lems_example

ref_outputs = run_lems_example("LEMS_NML2_Ex6_NMDA.xml")
for name, arr in ref_outputs.items():
    print(f"  {name}: shape={arr.shape}")
  ex6_block.dat: shape=(40001, 2)
  ex6_g.dat: shape=(40001, 2)
  ex6_v.dat: shape=(40001, 2)

4. Run TVBO

result = exp.run("neuroml")
da = result.integration.data
print(f"TVBO: {da.dims}, shape={da.shape}")
pyNeuroML >>> 12:59:31 - INFO - Loading LEMS file: tvbo_lems_sim.xml and running with jNeuroML
pyNeuroML >>> 12:59:31 - INFO - Executing: (java -Xmx400M  -Djava.awt.headless=true -jar  "/Users/leonmartin_bih/tools/tvbo/.venv/lib/python3.12/site-packages/pyneuroml/utils/./../lib/jNeuroML-0.14.0-jar-with-dependencies.jar"  tvbo_lems_sim.xml  -nogui -I '') in directory: /var/folders/ym/9kw1g21j1nd7kwfn8c0z3st40000gn/T/tmp5bdqawie
pyNeuroML >>> 12:59:33 - INFO - Command completed successfully!
TVBO: ('time', 'quantity'), shape=(40001, 1)

5. Compare & Plot

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