Multicompartment neurons
Tripod (AdEx soma, two passive dendrites d1, d2) and BallAndStick (one dendrite d).
| Group | Population field | Type | Default |
|---|---|---|---|
| morphology | param | DendNeuronParameter | TripodParameter() / BallAndStickParameter() |
| soma | adex | AdExParameter | AdExParameter() |
| spike shape, refractoriness | spike | PostSpike | PostSpike() |
| synapses | soma_syn, dend_syn | AbstractSynapseParameter | TripodSomaSynapse, 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
| Field | Default | Units | Meaning |
|---|---|---|---|
ds | [(200um, 400um), (200um, 400um)] | cm | one entry per dendrite: a length or a (min, max) range sampled per neuron in 1 μm steps |
physiology | human_dend | cable properties (Physiology) | |
geometry | [(:s=>:d1), (:s=>:d2)] | compartment graph, stored for bookkeeping | |
type | TripodNeuron() if length(ds) == 2, BallAndStickNeuron() if length(ds) == 1 | other lengths raise an error |
Shortcuts: TripodParameter, BallAndStickParameter. Predefined length ranges: proximal_distal, proximal_proximal, proximal, all_lengths.
Cable properties: Physiology
| Field | Meaning | human_dend | mouse_dend |
|---|---|---|---|
Ri | axial resistivity | 200 Ω cm | 200 Ω cm |
Rd | specific membrane resistance | 38907 Ω cm² | 1700 Ω cm² |
Cd | specific membrane capacitance | 0.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
| Field | Default | Units | Meaning |
|---|---|---|---|
AP_membrane | 10mV | mV | somatic potential during the spike |
up | 1ms | ms | duration of the clamped spike (back-propagation period) |
τabs | 1ms | ms | absolute refractory period after up |
At | 0mV | mV | threshold increment $A_t$ per spike |
τA | 10ms | ms | relaxation 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; usesC,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 withcreate_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 (Float32in both precisions).
State variables
v_s,v_d1,v_d2::VFT: compartment potentials (mV), initialised uniformly in[Vr, Vt].VFT = Vector{Float64}gives aFloat64population (seefloat_type):adex,spike, the synapse models and the dendrites follow, with the decimal default values;param(morphology) andVspikestayFloat32.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 toVt.spikes::SpikeIndex: neurons that fired in the step (seespike_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)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).
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 (seeTripod).dend_syn::SYND = TripodDendSynapse,soma_syn::SYNS = TripodSomaSynapse: synapse models.spike::PST = PostSpike(): spike shape and refractoriness.d::VDT:Dendritebuilt withcreate_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 aFloat64population, as forTripod.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 (seespike_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)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).
Dendrites, morphology and parameters
SNNModels.all_lengths — Constant
all_lengths = [(150um, 400um)]One dendrite with length drawn in 150-400 μm (BallAndStick ds).
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.
SNNModels.mouse_dend — Constant
mouse_dend :: Physiology{Float32}Mouse cortical dendrite: Ri = 200 Ω cm, Rd = 1700 Ω cm², Cd = 1 μF/cm².
SNNModels.proximal — Constant
proximal = [(150um, 300um)]One dendrite with length drawn in 150-300 μm (BallAndStick ds).
SNNModels.proximal_distal — Constant
proximal_distal = [(150um, 400um), (150um, 400um)]Two dendrites with lengths drawn in 150-400 μm (Tripod ds).
SNNModels.proximal_proximal — Constant
proximal_proximal = [(150um, 300um), (150um, 300um)]Two dendrites with lengths drawn in 150-300 μm (Tripod ds).
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 theTripod/BallAndStickdendritic equations.create_dendritesets it from itsElkeyword (default-70.6mV);TripodandBallAndStickpass the somaticadex.Elby default.l::VFT: compartment length (cm);-1marks 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]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)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$.
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 nSSNNModels.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}$.
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)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 whichcreate_dendritedraws the length of each neuron.physiology::PT = human_dend: cable properties (Physiology:Ri,Rd,Cd), used byTripodandBallAndStickto build their dendrites.geometry::GT = [(:s=>:d1), (:s=>:d2)]: connectivity of the compartments. Stored for bookkeeping;TripodandBallAndStickhard-code soma-dendrite coupling.type::NT:BallAndStickNeuron()iflength(ds) == 1,TripodNeuron()iflength(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 TripodSNNModels.BallAndStickParameter — Method
BallAndStickParameter(; ds = [(150um, 400um)], physiology = human_dend,
geometry = [(:s=>:d)]) -> DendNeuronParameterMorphology 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]))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.
SNNModels.TripodParameter — Method
TripodParameter(; ds = [(200um, 400um), (200um, 400um)], physiology = human_dend,
geometry = [(:s=>:d1), (:s=>:d2)]) -> DendNeuronParameterMorphology 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))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.