Interoperability · NeuroML / LEMS
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" } " )
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" )