Multicompartment neurons

Tripod (AdEx soma, two passive dendrites d1, d2) and BallAndStick (one dendrite d).

GroupPopulation fieldTypeDefault
morphologyparamDendNeuronParameterTripodParameter() / BallAndStickParameter()
somaadexAdExParameterAdExParameter()
spike shape, refractorinessspikePostSpikePostSpike()
synapsessoma_syn, dend_synAbstractSynapseParameterTripodSomaSynapse, TripodDendSynapse

A connection selects the compartment (:s, :d1, :d2; :s, :d) with its fourth argument:

using SpikingNeuralNetworks
SNN.@load_units
T = SNN.Tripod(N = 10)
E = SNN.Poisson(N = 50, param = SNN.PoissonParameter(20Hz))
I = SNN.Poisson(N = 50, param = SNN.PoissonParameter(20Hz))
E_d1 = SNN.SpikingSynapse(E, T, :glu, :d1; conn = (p = 0.2, μ = 2.0))   # first dendrite
E_d2 = SNN.SpikingSynapse(E, T, :glu, :d2; conn = (p = 0.2, μ = 2.0))   # second dendrite
I_s  = SNN.SpikingSynapse(I, T, :gaba, :s; conn = (p = 0.2, μ = 2.0))   # soma
model = SNN.compose(; E, I, T, E_d1, E_d2, I_s)
SNN.monitor!(T, [:v_s, :v_d1, :v_d2, :fire])
SNN.sim!(; model, duration = 500ms)

Equations

For dendrite $k$ ($k = 1, 2$ for Tripod, $k = 1$ for BallAndStick), with somatic parameters from adex and spike parameters from spike:

\[\begin{aligned} C \frac{dV_s}{dt} &= g_L (E_L - V_s) + g_L \Delta_T\, e^{(V_s - \theta)/\Delta_T} - w_s - I_{syn,s} - \sum_k g_{ax,k}\,(V_s - V_{d,k}) + I \\ C_{d,k} \frac{dV_{d,k}}{dt} &= g_{m,k} (E_{L,k} - V_{d,k}) - I_{syn,d,k} + g_{ax,k}\,(V_s - V_{d,k}) + I_d \\ \tau_w \frac{dw_s}{dt} &= a (V_s - E_L) - w_s \\ \tau_A \frac{d\theta}{dt} &= V_t - \theta \end{aligned}\]

$I_{syn}$ are the currents of the synapse models (clamped to $\pm 1500$ pA in Tripod, $\pm 1000$ pA in BallAndStick); $C_{d,k}$, $g_{m,k}$, $g_{ax,k}$ come from create_dendrite.

A spike is emitted when $V_s$ reaches Vspike (default $-10$ mV): $V_s$ is held at spike.AP_membrane for spike.up, then at adex.Vr for spike.τabs; $w_s \mathrel{+}= b$, $\theta \mathrel{+}= A_t$. Integration: Heun method.

Parameters

Morphology: DendNeuronParameter

FieldDefaultUnitsMeaning
ds[(200um, 400um), (200um, 400um)]cmone entry per dendrite: a length or a (min, max) range sampled per neuron in 1 μm steps
physiologyhuman_dendcable properties (Physiology)
geometry[(:s=>:d1), (:s=>:d2)]compartment graph, stored for bookkeeping
typeTripodNeuron() if length(ds) == 2, BallAndStickNeuron() if length(ds) == 1other lengths raise an error

Shortcuts: TripodParameter, BallAndStickParameter. Predefined length ranges: proximal_distal, proximal_proximal, proximal, all_lengths.

Cable properties: Physiology

FieldMeaninghuman_dendmouse_dend
Riaxial resistivity200 Ω cm200 Ω cm
Rdspecific membrane resistance38907 Ω cm²1700 Ω cm²
Cdspecific membrane capacitance0.5 μF/cm²1 μF/cm²

For a cylinder of length $l$ and diameter $d$:

\[G_{ax} = \frac{\pi d^2}{4 R_i l} \;(\texttt{G\_axial}), \qquad G_m = \frac{\pi d l}{R_d} \;(\texttt{G\_mem}), \qquad C = C_d\, \pi d l \;(\texttt{C\_mem}).\]

using SpikingNeuralNetworks
SNN.@load_units
SNN.G_axial(Ri = 200Ω*cm, d = 4um, l = 200um)       # ≈ 31.4 nS
d = SNN.create_dendrite(10, (150um, 300um); physiology = SNN.mouse_dend)
d.C[1], d.gm[1], d.gax[1]

Spike: PostSpike fields used

FieldDefaultUnitsMeaning
AP_membrane10mVmVsomatic potential during the spike
up1msmsduration of the clamped spike (back-propagation period)
τabs1msmsabsolute refractory period after up
At0mVmVthreshold increment $A_t$ per spike
τA10msmsrelaxation time constant of $\theta$

Synapses

Defaults: soma_syn = TripodSomaSynapse (AMPA + GABAa), dend_syn = TripodDendSynapse (AMPA + NMDA + GABAa + GABAb); see Synapse and receptor models.

Tripod

Reference: Quaresima et al. (2023), J. Physiol.

using SpikingNeuralNetworks
SNN.@load_units
T = SNN.Tripod(N = 10, param = SNN.TripodParameter(ds = SNN.proximal_distal),
               adex = SNN.AdExParameter(b = 0pA, a = 0nS))
T.I .= 300pA
SNN.monitor!(T, [:v_s, :fire])
SNN.sim!([T]; duration = 200ms)
SNNModels.Tripod — Type
Tripod(; N = 100, param = TripodParameter(), adex = AdExParameter(),
         soma_syn = TripodSomaSynapse, dend_syn = TripodDendSynapse, spike = PostSpike(), ...)

Population of three-compartment neurons: an AdEx-like soma coupled to two passive dendrites (d1, d2) through axial conductances. The dendritic geometry and cable properties are given by param (a DendNeuronParameter), the somatic parameters by adex, the somatic and dendritic synapses by soma_syn and dend_syn (any AbstractSynapseParameter with a five-argument synaptic_current!, i.e. not DeltaSynapse).

Connections select the compartment with the fourth argument of SpikingSynapse: SpikingSynapse(pre, T, :glu, :d1; conn), with targets :s, :d1, :d2.

Equations

Soma (AdEx-like, parameters from adex, an AdExParameter), for each dendrite $k$:

\[\begin{aligned} C \frac{dV_s}{dt} &= g_L (E_L - V_s) + g_L \Delta_T\, e^{(V_s - \theta)/\Delta_T} - w_s - I_{syn,s} - \sum_k g_{ax,k}\,(V_s - V_{d,k}) + I \\ C_{d,k} \frac{dV_{d,k}}{dt} &= g_{m,k} (E_{L,k} - V_{d,k}) - I_{syn,d,k} + g_{ax,k}\,(V_s - V_{d,k}) + I_d \\ \tau_w \frac{dw_s}{dt} &= a (V_s - E_L) - w_s \\ \tau_A \frac{d\theta}{dt} &= V_t - \theta \end{aligned}\]

$I_{syn,s}$ and $I_{syn,d,k}$ are computed by synaptic_current! of soma_syn and dend_syn with the compartment potentials of the Heun stage being evaluated, and are clamped to $\pm 1500$ pA (Tripod) or $\pm 1000$ pA (BallAndStick). $C_{d,k}$, $g_{m,k}$, $g_{ax,k}$ and the dendritic leak reversal $E_{L,k}$ come from the Dendrite structs (see create_dendrite); by default $E_{L,k}$ is the somatic $E_L$ (adex.El). The exponential term is multiplied by $g_L$, as in the AdEx model (Brette and Gerstner 2005) and in the published Tripod model (Quaresima et al. 2023, Eq. 1).

Spike: when the predicted somatic potential $V_s + dt\,\dot V_s$ reaches Vspike (population field, default $-10$ mV; adex.Vt is only the resting value of $\theta$), the neuron fires: $V_s \leftarrow$ AP_membrane, $w_s \leftarrow w_s + b$, $\theta \leftarrow \theta + A_t$, and the refractory counter is set to n_up + n_abs steps, with n_up = max(1, round(up/dt)) and n_abs = max(1, round(τabs/dt)). The soma is clamped at AP_membrane until the counter reaches n_abs (back-propagation period; the spike step itself counts as one), then at adex.Vr for n_abs steps; in both periods the dendrites only relax towards the soma through the axial term (forward Euler) and w_s is not integrated. $\theta$ relaxes to adex.Vt at every step (forward Euler). The published Tripod code (TripodNeuron.jl) detects spikes at $V_s \ge V_T$; Vspike = adex.Vt reproduces that rule.

Integration

Heun (explicit trapezoidal) method on $x = (V_s, V_{d,k}, w_s)$. Synaptic conductances are advanced first, once per step, by update_synapses!. Then $k_1 = f(x_n)$ is evaluated at the current state (stored in Δv_temp) and $k_2 = f(x_n + dt\,k_1)$ at the Euler-predicted state (stored in Δv); every term of $f$, including the synaptic currents, the axial currents and the adaptation current in the somatic equation, is evaluated at the same stage state. The state is advanced by $x_{n+1} = x_n + \frac{dt}{2}(k_1 + k_2)$. The scheme is second-order accurate between spikes.

Fields

Population info

  • id::String = randstring(12), name::String = "Tripod", N::IT = 100, records::Dict.

Parameters

  • param::DendNeuronParameter = TripodParameter(): morphology (ds, physiology).
  • adex::SOMAT = AdExParameter(): somatic parameters; uses C, gl, El, ΔT, Vt (resting value of the threshold $\theta$), Vr, a, b, τw.
  • soma_syn::SYNS = TripodSomaSynapse, dend_syn::SYND = TripodDendSynapse: synapse models.
  • spike::PST = PostSpike(): AP_membrane, up, τabs, At, τA.
  • d1::VDT, d2::VDT: Dendrites built with create_dendrite(N, param.ds[k]; El = adex.El, FT = eltype(VFT), physiology = param.physiology).
  • Vspike::Float32 = -10mV: spike detection threshold on the predicted somatic potential (Float32 in both precisions).

State variables

  • v_s, v_d1, v_d2::VFT: compartment potentials (mV), initialised uniformly in [Vr, Vt]. VFT = Vector{Float64} gives a Float64 population (see float_type): adex, spike, the synapse models and the dendrites follow, with the decimal default values; param (morphology) and Vspike stay Float32.
  • w_s::VFT: somatic adaptation current (pA), zeros.
  • I::VFT: external current into the soma (pA); I_d::VFT: external current injected in each of the two dendrites (pA).
  • fire::VBT: spike flags; tabs::VFT: refractory counters (steps); θ::VFT: dynamic threshold of the exponential term (mV), initialised to Vt.
  • spikes::SpikeIndex: neurons that fired in the step (see spike_index).

Synapses

  • synvars_s, synvars_d1, synvars_d2: synaptic state variables (synaptic_variables).
  • receptors_s, receptors_d1, receptors_d2::NamedTuple: input buffers (synaptic_receptors).

Work arrays

  • Δv, Δv_temp::MFT (N x 4): derivatives of (v_s, v_d1, v_d2, w_s) at the two Heun stages.
  • is::MFT (N x 3): synaptic currents of soma, d1, d2; ic::VFT (length 2): unused, kept for compatibility; v_pred::MFT (N x 3): stage potentials of soma, d1, d2 (mV).

References

Quaresima A. et al. (2023), "The Tripod neuron: a minimal structural reduction of the dendritic tree", J. Physiol. Receptor parameters: see TripodSomaSynapse and TripodDendSynapse.

Example

using SpikingNeuralNetworks
SNN.@load_units
T = SNN.Tripod(N = 10)
E = SNN.Poisson(N = 50, param = SNN.PoissonParameter(20Hz))
syn = SNN.SpikingSynapse(E, T, :glu, :d1; conn = (p = 0.2, μ = 2.0))
model = SNN.compose(; E, T, syn)
SNN.monitor!(T, [:v_s, :v_d1, :fire])
SNN.sim!(; model, duration = 200ms)
source
SNNModels.integrate! — Method
integrate!(p::Tripod, param::DendNeuronParameter, dt::AbstractFloat)

Advance a Tripod population by dt: update the synapses of the three compartments, then integrate the membrane equations with the Heun method and handle spikes and refractoriness (see Tripod).

source

BallAndStick

using SpikingNeuralNetworks
SNN.@load_units
B = SNN.BallAndStick(N = 10, param = SNN.BallAndStickParameter(ds = [300um]))
E = SNN.Poisson(N = 50, param = SNN.PoissonParameter(20Hz))
syn = SNN.SpikingSynapse(E, B, :glu, :d; conn = (p = 0.2, μ = 2.0))
model = SNN.compose(; E, B, syn)
SNN.sim!(; model, duration = 200ms)
SNNModels.BallAndStick — Type
BallAndStick(; N = 100, param = BallAndStickParameter(), adex = AdExParameter(),
               soma_syn = TripodSomaSynapse, dend_syn = TripodDendSynapse, spike = PostSpike(), ...)

Population of two-compartment neurons: an AdEx-like soma coupled to one passive dendrite (d) through an axial conductance. Same equations, spike rule and Heun integration as Tripod with a single dendrite; the synaptic currents are clamped to $\pm 1000$ pA and the external currents are Is (soma) and Id (dendrite). Connections select the compartment with the fourth argument of SpikingSynapse: targets :s and :d.

Fields

Population info

  • name::String = "BallAndStick", id::String = randstring(12), N::IT = 100, records::Dict.

Parameters

  • param::DendNeuronParameter = BallAndStickParameter(): morphology.
  • adex::SOMAT = AdExParameter(): somatic parameters (see Tripod).
  • dend_syn::SYND = TripodDendSynapse, soma_syn::SYNS = TripodSomaSynapse: synapse models.
  • spike::PST = PostSpike(): spike shape and refractoriness.
  • d::VDT: Dendrite built with create_dendrite(N, param.ds[1]; El = adex.El, FT = eltype(VFT), physiology = param.physiology).
  • Vspike::Float32 = -10mV: spike detection threshold on the predicted somatic potential.

State variables

  • v_s, v_d::VFT: somatic and dendritic potentials (mV), initialised uniformly in [Vr, Vt]. VFT = Vector{Float64} gives a Float64 population, as for Tripod.
  • w_s::VFT: somatic adaptation current (pA).
  • Is, Id::VFT: external currents into the soma and the dendrite (pA), zeros.
  • fire::VBT, tabs::VFT, θ::VFT: spike flags, refractory counters (steps), dynamic threshold (mV).
  • spikes::SpikeIndex: neurons that fired in the step (see spike_index).

Synapses

  • synvars_s, synvars_d: synaptic state variables; receptors_s, receptors_d::NamedTuple: input buffers.

Work arrays

  • Δv, Δv_temp::MFT (N x 3): derivatives of (v_s, v_d, w_s); is::MFT (N x 2); ic::VFT (length 1): unused, kept for compatibility; v_pred::MFT (N x 2): stage potentials of soma and dendrite.

Example

using SpikingNeuralNetworks
SNN.@load_units
B = SNN.BallAndStick(N = 10)
E = SNN.Poisson(N = 50, param = SNN.PoissonParameter(20Hz))
syn = SNN.SpikingSynapse(E, B, :glu, :d; conn = (p = 0.2, μ = 2.0))
model = SNN.compose(; E, B, syn)
SNN.sim!(; model, duration = 200ms)
source
SNNModels.integrate! — Method
integrate!(p::BallAndStick, param::DendNeuronParameter, dt::AbstractFloat)

Advance a BallAndStick population by dt (synapses, Heun step of soma and dendrite, spikes and refractoriness; see BallAndStick).

source

Dendrites, morphology and parameters

SNNModels.human_dend — Constant
human_dend :: Physiology{Float32}

Human cortical dendrite: Ri = 200 Ω cm, Rd = 38907 Ω cm², Cd = 0.5 μF/cm². Default physiology of TripodParameter, BallAndStickParameter and create_dendrite.

source
SNNModels.mouse_dend — Constant
mouse_dend :: Physiology{Float32}

Mouse cortical dendrite: Ri = 200 Ω cm, Rd = 1700 Ω cm², Cd = 1 μF/cm².

source
SNNModels.proximal — Constant
proximal = [(150um, 300um)]

One dendrite with length drawn in 150-300 μm (BallAndStick ds).

source
SNNModels.Dendrite — Type
Dendrite(; N = 100, El, l, d, C, gax, gm)

Passive properties of one dendritic compartment for each of the N neurons of a dendritic population (Tripod has two, d1 and d2; BallAndStick has one, d). Normally built with create_dendrite(N, l).

Fields (vectors of type VFT and length N, default zeros(N))

  • N::Int32 = 100: number of neurons.
  • El::VFT: leak reversal (resting) potential of the dendrite (mV), used by the Tripod/BallAndStick dendritic equations. create_dendrite sets it from its El keyword (default -70.6mV); Tripod and BallAndStick pass the somatic adex.El by default.
  • l::VFT: compartment length (cm); -1 marks a disconnected compartment (l <= 0).
  • d::VFT: compartment diameter (cm).
  • C::VFT: membrane capacitance (pF), C_mem.
  • gax::VFT: axial conductance to the soma (nS), G_axial.
  • gm::VFT: membrane leak conductance (nS), G_mem.

Example

using SpikingNeuralNetworks
SNN.@load_units
d = SNN.create_dendrite(10, (150um, 300um))   # 10 dendrites, length uniform in 150-300 μm
d.gax[1], d.C[1]
source
SNNModels.Physiology — Type
Physiology(Ri, Rd, Cd)
Physiology(; Ri, Rd, Cd)

Passive cable properties of a dendrite, per unit length or area, in the library unit system.

Fields

  • Ri::T: axial (intracellular) resistivity, e.g. 200Ω*cm (stored in GΩ cm).
  • Rd::T: specific membrane resistance, e.g. 38907Ω*cm^2 (stored in GΩ cm²).
  • Cd::T: specific membrane capacitance, e.g. 0.5μF/cm^2 (stored in pF/cm²).

Predefined: human_dend (Ri = 200 Ω cm, Rd = 38907 Ω cm², Cd = 0.5 μF/cm²) and mouse_dend (Ri = 200 Ω cm, Rd = 1700 Ω cm², Cd = 1 μF/cm²). References for these values are not given in the code.

Example

using SpikingNeuralNetworks
SNN.@load_units
phys = SNN.Physiology(Ri = 150Ω*cm, Rd = 20000Ω*cm^2, Cd = 1μF/cm^2)
source
SNNModels.C_mem — Method
C_mem(; Cd, d, l)

Membrane capacitance (pF) of the lateral surface of a cylinder of length l and diameter d (cm) with specific capacitance Cd (pF/cm²): $C = C_d\,\pi d l$.

source
SNNModels.G_axial — Method
G_axial(; Ri, d, l)

Axial conductance (nS) of a cylinder of length l and diameter d (cm, e.g. 200um) with axial resistivity Ri (GΩ cm, e.g. 200Ω*cm): $G_{ax} = \frac{\pi d^2}{4 R_i l}$.

Example

using SpikingNeuralNetworks
SNN.@load_units
SNN.G_axial(Ri = 200Ω*cm, d = 4um, l = 200um)   # ≈ 31.4 nS
source
SNNModels.G_mem — Method
G_mem(; Rd, d, l)

Membrane (leak) conductance (nS) of the lateral surface of a cylinder of length l and diameter d (cm) with specific membrane resistance Rd (GΩ cm²): $G_m = \frac{\pi d l}{R_d}$.

source
SNNModels.create_dendrite — Method
create_dendrite(N::Int, l; El = -70.6mV, d = 4um, physiology = human_dend, FT = Float32) -> Dendrite
create_dendrite(l; d = 4um, physiology = human_dend) -> NamedTuple
create_dendrite(; l, kwargs...)

Compute the passive parameters of a cylindrical dendrite of length l and diameter d from the cable properties physiology (Physiology).

l is either a length (cm, e.g. 200um) or a tuple (lmin, lmax), in which case the length is drawn uniformly from lmin:1um:lmax (independently for each of the N neurons in the first form). Lengths above 500um raise an error. For l > 0 it returns (gm = G_mem(Rd, d, l), gax = G_axial(Ri, d, l), C = C_mem(Cd, d, l), l, d); for l <= 0 it returns a disconnected compartment (gm = 1, gax = 0, C = 1, l = -1, d). The N form returns a Dendrite{Vector{FT}} with these values per neuron and leak reversal El.

Precision: with FT = Float32 the geometry is computed with the Float32 unit constants. With FT = Float64 it is computed from the decimal values the arguments denote (5um, stored as 0.00049999997f0, is read as 0.0005; the cable constants likewise in their units). A range is sampled with the same RNG draws as in Float32, so the same seed gives the same lengths in both precisions.

Example

using SpikingNeuralNetworks
SNN.@load_units
SNN.create_dendrite(200um)                          # one dendrite, human physiology
SNN.create_dendrite(5, (150um, 400um); physiology = SNN.mouse_dend)
source
SNNModels.DendNeuronParameter — Type
DendNeuronParameter(; ds = [(200um, 400um), (200um, 400um)], physiology = human_dend,
                      geometry = [(:s=>:d1), (:s=>:d2)], type = <from length(ds)>)

Parameter struct of the multicompartment dendritic populations (Tripod, BallAndStick). It carries the morphology only; the somatic parameters are in the population field adex (an AdExParameter) and the synapses in soma_syn/dend_syn.

Population(param::DendNeuronParameter; kwargs...) builds a Tripod when type is TripodNeuron() and a BallAndStick when it is BallAndStickNeuron().

Fields

  • ds::DT = [(200um, 400um), (200um, 400um)]: one entry per dendrite, either a length (cm) or a (min, max) range from which create_dendrite draws the length of each neuron.
  • physiology::PT = human_dend: cable properties (Physiology: Ri, Rd, Cd), used by Tripod and BallAndStick to build their dendrites.
  • geometry::GT = [(:s=>:d1), (:s=>:d2)]: connectivity of the compartments. Stored for bookkeeping; Tripod and BallAndStick hard-code soma-dendrite coupling.
  • type::NT: BallAndStickNeuron() if length(ds) == 1, TripodNeuron() if length(ds) == 2; other lengths raise an error.

Type parameters: DT = Vector{DendLength} (DendLength = Union{Float32,Tuple}), GT = Vector{Pair{Symbol,Symbol}}, PT = Physiology{Float32}, NT<:AbstractDendriticTree.

The dendrite diameter is the create_dendrite default, d = 4um.

Example

using SpikingNeuralNetworks
SNN.@load_units
param = SNN.DendNeuronParameter(ds = [(150um, 300um), (300um, 400um)], physiology = SNN.mouse_dend)
T = SNN.Population(param; N = 10)   # a Tripod
source
SNNModels.BallAndStickParameter — Method
BallAndStickParameter(; ds = [(150um, 400um)], physiology = human_dend,
                        geometry = [(:s=>:d)]) -> DendNeuronParameter

Morphology of a BallAndStick neuron: soma plus one dendrite of length ds[1]. ds must have one entry.

Example

using SpikingNeuralNetworks
SNN.@load_units
B = SNN.BallAndStick(N = 10, param = SNN.BallAndStickParameter(ds = [300um]))
source
SNNModels.Population — Method
Population(param::DendNeuronParameter; kwargs...)

Build a Tripod (two dendrites) or a BallAndStick (one dendrite) population according to param.type; kwargs are passed to the population constructor.

source
SNNModels.TripodParameter — Method
TripodParameter(; ds = [(200um, 400um), (200um, 400um)], physiology = human_dend,
                  geometry = [(:s=>:d1), (:s=>:d2)]) -> DendNeuronParameter

Morphology of a Tripod neuron: soma plus two dendrites with lengths ds[1], ds[2]. ds must have two entries.

Example

using SpikingNeuralNetworks
SNN.@load_units
T = SNN.Tripod(N = 10, param = SNN.TripodParameter(ds = SNN.proximal_distal))
source
SNNModels.synaptic_target — Method
synaptic_target(targets::Dict, post::AbstractDendriteIF, sym::Symbol, target::Symbol)

Target the receptor buffer post.receptors_<target>.<sym> of compartment target (:s, :d1, :d2 for Tripod; :s, :d for BallAndStick); sym is mapped with get_synapse_symbol (:ge/:he -> :glu, :gi/:hi -> :gaba). Returns the buffer and post.v_<target>. Records :sym => "<sym>_<target>" in targets. An unknown target raises an ArgumentError.

source