Ex15: Calcium Dynamics

Intracellular calcium concentration pool and calcium-dependent K channels

Model: Calcium Dynamics

Demonstrates decayingPoolConcentrationModel — a first-order calcium pool:

\[\frac{d[\text{Ca}^{2+}]}{dt} = -\frac{I_{Ca}}{2 F \cdot \text{shell}} - \frac{[\text{Ca}^{2+}] - [\text{Ca}^{2+}]_{\text{rest}}}{\tau}\]

This is a granule cell with 7 channel types (Na, KDr, H, CaHVA, KA, KCa, leak) plus the Ca concentration pool. All are expressible as TVBO state variables and derived variables.


1. Define HH Cell in TVBO

from tvbo import SimulationExperiment

# Standard HH representing the core membrane dynamics
exp = SimulationExperiment.from_string("""
label: "NeuroML Ex15: HH Cell (Ca Dynamics)"
dynamics:
  name: HodgkinHuxley
  parameters:
    C:     { value: 10.0 }
    g_Na:  { value: 1200.0 }
    g_K:   { value: 360.0 }
    g_L:   { value: 3.0 }
    E_Na:  { value: 55.0 }
    E_K:   { value: -90.0 }
    E_L:   { value: -65.0 }
    I_ext: { value: 0.01 }
  derived_variables:
    alpha_m:
      equation:
        rhs: "Piecewise((1.0, Eq(v, -40.0)), (0.1*(v + 40.0)/(1.0 - exp(-(v + 40.0)/10.0)), True))"
    beta_m:
      equation:
        rhs: "4.0*exp(-(v + 65.0)/18.0)"
    alpha_h:
      equation:
        rhs: "0.07*exp(-(v + 65.0)/20.0)"
    beta_h:
      equation:
        rhs: "1.0/(1.0 + exp(-(v + 35.0)/10.0))"
    alpha_n:
      equation:
        rhs: "Piecewise((0.1, Eq(v, -55.0)), (0.01*(v + 55.0)/(1.0 - exp(-(v + 55.0)/10.0)), True))"
    beta_n:
      equation:
        rhs: "0.125*exp(-(v + 65.0)/80.0)"
  state_variables:
    v:
      equation:
        rhs: "(-g_Na*m**3*h*(v - E_Na) - g_K*n**4*(v - E_K) - g_L*(v - E_L) + I_ext*1000) / C"
      initial_value: -65.0
      variable_of_interest: true
    m:
      equation: { rhs: "alpha_m*(1 - m) - beta_m*m" }
      initial_value: 0.05
    h:
      equation: { rhs: "alpha_h*(1 - h) - beta_h*h" }
      initial_value: 0.6
    n:
      equation: { rhs: "alpha_n*(1 - n) - beta_n*n" }
      initial_value: 0.32
network:
  number_of_nodes: 1
integration:
  method: euler
  step_size: 0.01
  duration: 700.0
  time_scale: ms
""")
print(f"Model: {exp.dynamics.name}")
Model: HodgkinHuxley

2. Render LEMS XML

xml = exp.render("lems")
print(xml[:1200])

<Lems>

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

  <!-- ════════════════════════════════════════════════════════════════
       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"/>
  <Un

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_Ex15_CaDynamics.xml")
for name, arr in ref_outputs.items():
    print(f"  {name}: shape={arr.shape}")
  ex15_cond_dens.dat: shape=(700001, 6)
  ex15_curr_dens.dat: shape=(700001, 6)
  ex15_v.dat: shape=(700001, 2)

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}")
TVBO: shape=(70001, 5)

5. Plot Reference (Full Granule Cell)

import matplotlib.pyplot as plt
import numpy as np

for name, ref_arr in ref_outputs.items():
    t = ref_arr[:, 0] * 1000
    fig, ax = plt.subplots(figsize=(10, 4))
    for i in range(1, min(ref_arr.shape[1], 4)):
        ax.plot(t, ref_arr[:, i], alpha=0.8, label=f'col {i}')
    ax.set_xlabel("Time (ms)")
    ax.set_title(f"Ex15: Ca Dynamics — {name}")
    ax.legend(fontsize=7)
    ax.grid(True, alpha=0.3)
    plt.tight_layout()
    plt.show()

Ca Dynamics in TVBO

The calcium pool ODE and Ca-dependent channel rates are expressible as TVBO state variables and derived variables. The full model (~17 state variables) could be defined as a single TVBO Dynamics.