The problem is that the NMODL code for this synaptic mechanism is written in such a way that it cannot properly handle events delivered by multiple NetCons.
This is a simple implementation of a saturating synapse. At initialization, the synapse is "off" and the forward rate constant r1 is 0 in the kinetic scheme that governs the fraction of open channels
~ C <-> O (r1,1/tau2)
so that C == 1 and O (the open fraction) is 0.
Arrival of an input event (an event with flag==0) switches the synapse to "on" and makes r1 nonzero (think "transmitter in synaptic cleft"). It also launches a self-event that arrives Cdur ms later. If no additional input events arrive while the synapse is "on", arrival of the self-event will turn r1 back to 1 and the open fraction O will decay back to 0. Each input event that arrives while the synapse is "on" merely prolongs the duration over which r1 is nonzero, i.e. prolongs the "presence of transmitter in the synaptic cleft".
So a single instance of this mechanism cannot summate multiple input streams. If you have multiple input streams but want to continue using this mechanism, you're stuck with having to give each input stream (each NetCon) its own synaptic mechanism instance.
Further comments:
The units for tau1, tau2, Tmax, and T are rubbish. They should clearly be ms, ms, 1, and 1.
Example 10.6: Saturating synapses in the NEURON Book (pages 284 et seq.) presents the NMODL code for a synaptic mechanism that not only implements receptor saturation, but also properly and efficiently handles summation of multiple input streams. Here it is:
- Code: Select all
: ampa.mod
: saturating synapse model using discrete events
NEURON {
POINT_PROCESS AMPA_S
RANGE g
NONSPECIFIC_CURRENT i
GLOBAL Cdur, Alpha, Beta, Erev, Rinf, Rtau
}
UNITS {
(nA) = (nanoamp)
(mV) = (millivolt)
(umho) = (micromho)
}
PARAMETER {
Cdur = 1.0 (ms) : transmitter duration (rising phase)
Alpha = 1.1 (/ms) : forward (binding) rate
Beta = 0.19 (/ms) : backward (dissociation) rate
Erev = 0 (mV) : equilibrium potential
}
ASSIGNED {
v (mV) : postsynaptic voltage
i (nA) : current = g*(v - Erev)
g (umho) : conductance
Rtau (ms) : time constant of channel binding
Rinf : fraction of open channels if xmtr was present "forever"
synon : sum of weights of all synapses that are in the "onset" state
}
STATE { Ron Roff } : initialized to 0 by default
: Ron and Roff are the total conductances of all synapses
: that are in the "onset" (transmitter pulse ON)
: and "offset" (transmitter pulse OFF) states, respectively
INITIAL {
Rinf = Alpha / (Alpha + Beta)
Rtau = 1 / (Alpha + Beta)
synon = 0
}
BREAKPOINT {
SOLVE release METHOD cnexp
g = (Ron + Roff)*1(umho)
i = g*(v - Erev)
}
DERIVATIVE release {
Ron' = (synon*Rinf - Ron)/Rtau
Roff' = -Beta*Roff
}
NET_RECEIVE(weight, on, r0, t0 (ms)) {
: on == 1 if transmitter is present ("onset" state), otherwise 0
: flag is an implicit argument of NET_RECEIVE, normally 0
if (flag == 0) {
: a spike happened, so start onset state if not already in onset state
if (!on) {
: this synapse joins the set of synapses in the onset state
synon = synon + weight
r0 = r0*exp(-Beta*(t - t0)) : r0 at start of onset state
: r0 joins the "onset" conductance pool,
: which grows according to Ron' = ...
: and leaves the "offset" conductance pool,
: which decays according to Roff' = ...
Ron = Ron + r0
Roff = Roff - r0
t0 = t
on = 1
net_send(Cdur, 1)
} else {
: already in onset state, so move offset time
net_move(t+Cdur)
}
}
if (flag == 1) {
: "turn off transmitter"
: i.e. this synapse joins the set of synapses in the offset state
synon = synon - weight
: r0 at start of offset state
r0 = weight*Rinf + (r0 - weight*Rinf)*exp(-(t - t0)/Rtau)
: r0 leaves the "onset" conductance pool,
: and joins the "offset" conductance pool
Ron = Ron - r0
Roff = Roff + r0
t0 = t
on = 0
}
}