copying to personal repo
This commit is contained in:
22
cnmodel/synapses/__init__.py
Normal file
22
cnmodel/synapses/__init__.py
Normal file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Synapse definitions for models.
|
||||
#
|
||||
# This file includes a number of different synapse definitions and default conductances
|
||||
# for point models. Most are models from the lab for neurons of the cochlear nucleus.
|
||||
# the synaptic receptor models are gleaned from the literature and sometimes fitted to the
|
||||
# cochlear nucleus data.
|
||||
#
|
||||
# Paul B. Manis, Ph.D. 2009 (August - November 2009)
|
||||
#
|
||||
from neuron import h
|
||||
import numpy as np
|
||||
|
||||
from .synapse import Synapse
|
||||
from .terminal import Terminal
|
||||
from .psd import PSD
|
||||
from .glu_psd import GluPSD
|
||||
from .gly_psd import GlyPSD
|
||||
from .stochastic_terminal import StochasticTerminal
|
||||
from .simple_terminal import SimpleTerminal
|
||||
from .exp2_psd import Exp2PSD
|
||||
75
cnmodel/synapses/exp2_psd.py
Normal file
75
cnmodel/synapses/exp2_psd.py
Normal file
@@ -0,0 +1,75 @@
|
||||
import numpy as np
|
||||
from neuron import h
|
||||
|
||||
from .psd import PSD
|
||||
|
||||
|
||||
class Exp2PSD(PSD):
|
||||
"""
|
||||
Simple double-exponential PSD from Neuron (fast).
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, section, terminal, weight=0.01, loc=0.5, tau1=0.1, tau2=0.3, erev=0
|
||||
):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
section : Section
|
||||
The postsynaptic section in which to insert the receptor mechanism.
|
||||
terminal : Terminal
|
||||
The presynaptic Terminal instance
|
||||
weight :
|
||||
loc : float, default=0.5
|
||||
Position on the postsynaptic section to insert the mechanism, from [0..1].
|
||||
|
||||
"""
|
||||
PSD.__init__(self, section, terminal)
|
||||
self.syn = h.Exp2Syn(loc, sec=section)
|
||||
self.syn.tau1 = tau1
|
||||
self.syn.tau2 = tau2
|
||||
self.syn.e = erev
|
||||
|
||||
terminal.connect(self.syn, weight=weight)
|
||||
|
||||
@property
|
||||
def n_psd(self):
|
||||
"""The number of postsynaptic densities represented by this object.
|
||||
"""
|
||||
return 1
|
||||
|
||||
def record(self, *args):
|
||||
"""Create a new set of vectors to record parameters for each release
|
||||
site.
|
||||
|
||||
|
||||
Parameters
|
||||
----------
|
||||
\*args :
|
||||
Allowed parameters are 'i' (current), 'g' (conductnace), and 'Open' (open probability).
|
||||
|
||||
"""
|
||||
self.vectors = {"ampa": [], "nmda": []}
|
||||
for receptor in self.vectors:
|
||||
for mech in getattr(self, receptor + "_psd"):
|
||||
vec = {}
|
||||
for var in args:
|
||||
vec[var] = h.Vector()
|
||||
vec[var].record(getattr(mech, "_ref_" + var))
|
||||
self.vectors[receptor].append(vec)
|
||||
|
||||
def get_vector(self, var):
|
||||
"""Return an array from a previously recorded vector.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
receptor : str
|
||||
May be 'ampa' or 'nmda'
|
||||
var : str
|
||||
Allowed parameters are 'i' (current), 'g' (conductance), and 'Open' (open probability).
|
||||
i : int, default=0
|
||||
The integer index of the psd (if this is a multi-site synapse)
|
||||
|
||||
"""
|
||||
v = self.vectors[receptor][i][var]
|
||||
return np.array(v)
|
||||
146
cnmodel/synapses/glu_psd.py
Normal file
146
cnmodel/synapses/glu_psd.py
Normal file
@@ -0,0 +1,146 @@
|
||||
import numpy as np
|
||||
from neuron import h
|
||||
|
||||
from .psd import PSD
|
||||
|
||||
|
||||
class GluPSD(PSD):
|
||||
"""
|
||||
Glutamatergic PSD with ionotropic AMPA / NMDA receptors
|
||||
|
||||
This creates a set of postsynaptoc NMDA and AMPA receptors, one pair
|
||||
per terminal release site. Receptors are connected to the XMTR range
|
||||
variable of the terminal release mechanisms.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
section : Section instance
|
||||
The postsynaptic section into which the receptor mechanisms should be
|
||||
attached
|
||||
terminal : Terminal instance
|
||||
The presynaptic terminal that provides input to the receptor XMTR
|
||||
variables.
|
||||
ampa_gmax : float
|
||||
Maximum conductance of AMPARs
|
||||
nmda_gmax : float
|
||||
Maximum conductance of NMDARs
|
||||
gvar : float
|
||||
Coefficient of variation for randomly adjusting ampa_gmax and nmda_gmax.
|
||||
Note that ampa and nmda maximum conductances will be scaled together,
|
||||
but the scale values will be selected randomly for each pair of
|
||||
receptor mechanisms.
|
||||
eRev : float
|
||||
Reversal potential to use for both receptor types.
|
||||
ampa_params : dict
|
||||
Dictionary containing kinetic parameters for AMPA mechanism. Suggested
|
||||
keys are Ro1, Ro2, Rc1, Rc2, and PA.
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
*ampa_gmax* and *nmda_gmax* should be provided as the maximum *measured*
|
||||
conductances; these will be automatically corrected for the maximum open
|
||||
probability of the receptor mechanisms.
|
||||
|
||||
GluPSD does not include a cleft mechanism because AMPATRUSSELL implements
|
||||
its own cleft and NMDA_Kampa is slow enough that a cleft would have
|
||||
insignificant effect.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
section,
|
||||
terminal,
|
||||
ampa_gmax,
|
||||
nmda_gmax,
|
||||
gvar=0,
|
||||
eRev=0,
|
||||
nmda_vshift=0,
|
||||
ampa_params=None,
|
||||
loc=0.5,
|
||||
):
|
||||
PSD.__init__(self, section, terminal)
|
||||
# print('\033[0;33;40m ^^^^^ GVAR = %.4f ^^^^^\033[0;37;40m ' % gvar)
|
||||
ampa_params = {} if ampa_params is None else ampa_params
|
||||
|
||||
# and then make a set of postsynaptic receptor mechanisms
|
||||
ampa_psd = []
|
||||
nmda_psd = []
|
||||
relsite = terminal.relsite
|
||||
self.section.push()
|
||||
for i in range(0, terminal.n_rzones):
|
||||
# create mechanisms
|
||||
ampa = h.AMPATRUSSELL(
|
||||
loc, self.section
|
||||
) # raman/trussell AMPA with rectification
|
||||
nmda = h.NMDA_Kampa(loc, self.section) # Kampa state model NMDA receptors
|
||||
|
||||
# Connect terminal to psd
|
||||
h.setpointer(relsite._ref_XMTR[i], "XMTR", ampa)
|
||||
h.setpointer(relsite._ref_XMTR[i], "XMTR", nmda)
|
||||
|
||||
# Set any extra ampa parameters provided by the caller
|
||||
# (Ro1, Ro2, Rc1, Rc2, PA, ...)
|
||||
for k, v in ampa_params.items():
|
||||
setattr(ampa, k, v)
|
||||
|
||||
# add a little variability - gvar is CV of amplitudes
|
||||
v = 1.0 + gvar * np.random.standard_normal()
|
||||
|
||||
# set gmax and eRev for each postsynaptic receptor mechanism
|
||||
ampa.gmax = ampa_gmax * v
|
||||
ampa.Erev = eRev
|
||||
nmda.gmax = nmda_gmax * v
|
||||
nmda.Erev = eRev
|
||||
nmda.vshift = nmda_vshift
|
||||
|
||||
ampa_psd.append(ampa)
|
||||
nmda_psd.append(nmda)
|
||||
|
||||
h.pop_section()
|
||||
|
||||
self.ampa_psd = ampa_psd
|
||||
self.nmda_psd = nmda_psd
|
||||
self.all_psd = nmda_psd + ampa_psd
|
||||
|
||||
@property
|
||||
def n_psd(self):
|
||||
"""The number of postsynaptic densities represented by this object.
|
||||
"""
|
||||
return len(self.ampa_psd)
|
||||
|
||||
def record(self, *args):
|
||||
"""Create a new set of vectors to record parameters for each release
|
||||
site.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
\*args :
|
||||
Allowed parameters are 'i' (current), 'g' (conductance), and 'Open' (open probability).
|
||||
|
||||
"""
|
||||
self.vectors = {"ampa": [], "nmda": []}
|
||||
for receptor in self.vectors:
|
||||
for mech in getattr(self, receptor + "_psd"):
|
||||
vec = {}
|
||||
for var in args:
|
||||
vec[var] = h.Vector()
|
||||
vec[var].record(getattr(mech, "_ref_" + var))
|
||||
self.vectors[receptor].append(vec)
|
||||
|
||||
def get_vector(self, receptor, var, i=0):
|
||||
"""Return an array from a previously recorded vector.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
receptor : str
|
||||
May be 'ampa' or 'nmda'
|
||||
var : str
|
||||
Allowed parameters are 'i' (current), 'g' (conductance), and 'Open' (open probability).
|
||||
i : int, default=0
|
||||
The integer index of the psd (if this is a multi-site synapse)
|
||||
|
||||
"""
|
||||
v = self.vectors[receptor][i][var]
|
||||
return np.array(v)
|
||||
398
cnmodel/synapses/gly_psd.py
Normal file
398
cnmodel/synapses/gly_psd.py
Normal file
@@ -0,0 +1,398 @@
|
||||
from __future__ import print_function
|
||||
import numpy as np
|
||||
from neuron import h
|
||||
|
||||
from .psd import PSD
|
||||
|
||||
|
||||
class GlyPSD(PSD):
|
||||
"""Glycinergic PSD
|
||||
|
||||
This creates postsynaptoc glycinergic receptors. Receptors are connected to the XMTR range
|
||||
variable of the terminal release mechanisms.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
section : Section
|
||||
The postsynaptic section in which to insert the receptor mechanism.
|
||||
terminal : Terminal
|
||||
The presynaptic Terminal instance
|
||||
params : dict, default=None
|
||||
Dictionary of kinetic parameters to override {'KV', 'KU', 'XMax'}
|
||||
gmax : float, default=1000.
|
||||
maximal conductance unless overridden by values used in psdType
|
||||
psdType : str, default='glyfast'
|
||||
Kinetic model of receptors: possiblities are:
|
||||
glyfast, glyslow, glyGC, glya5, or glyexp, as defined in the mechanisms.
|
||||
message : str, default: None
|
||||
placeholder for a message to be printed out when testing.
|
||||
debug: bool, default=False
|
||||
enable printing of internal debugging messages.
|
||||
gvar : float, default=0
|
||||
coefficient of variation of the amplitudes for each of the release zones.
|
||||
eRev : float, default=-70
|
||||
"Reversal" potential, or Nernst potential for ions through the receptor channel.
|
||||
loc : float, default=0.5
|
||||
Position on the postsynaptic section to insert the mechanism, from [0..1].
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
section,
|
||||
terminal,
|
||||
params=None,
|
||||
gmax=1000.0,
|
||||
psdType="glyfast",
|
||||
message=None,
|
||||
debug=False,
|
||||
gvar=0,
|
||||
eRev=-70,
|
||||
loc=0.5,
|
||||
):
|
||||
|
||||
PSD.__init__(self, section, terminal)
|
||||
pre_sec = terminal.section
|
||||
post_sec = section
|
||||
|
||||
from .. import cells
|
||||
|
||||
params = {} if params is None else params
|
||||
|
||||
self.pre_cell = cells.cell_from_section(pre_sec)
|
||||
self.post_cell = cells.cell_from_section(post_sec)
|
||||
|
||||
self.psdType = psdType
|
||||
self.gmax = gmax
|
||||
glyslowPoMax = (
|
||||
0.162297
|
||||
) # thse were measured from the kinetic models in Synapses.py, as peak open P for the glycine receptors
|
||||
glyfastPoMax = 0.038475 # also later verified, same numbers...
|
||||
if self.psdType == "glyfast":
|
||||
gmax /= (
|
||||
glyfastPoMax
|
||||
) # normalized to maximum open probability for this receptor
|
||||
if self.psdType == "glyslow":
|
||||
gmax /= glyslowPoMax # normalized to max open prob for the slow receptor.
|
||||
|
||||
# print "Stochastic syn: j = %d of n_fibers = %d n_rzones = %d\n" % (j, n_fibers, n_rzones)
|
||||
relzone = terminal.relsite
|
||||
n_rzones = terminal.n_rzones
|
||||
|
||||
#
|
||||
# Create cleft mechanisms
|
||||
#
|
||||
clefts = []
|
||||
for k in range(0, n_rzones):
|
||||
cl = h.cleftXmtr(loc, sec=post_sec)
|
||||
clefts.append(cl)
|
||||
|
||||
# and then make a set of postsynaptic receptor mechanisms
|
||||
if self.psdType == "glyslow":
|
||||
(psd, par) = self.template_Gly_PSD_State_Gly6S(
|
||||
nReceptors=n_rzones, psdtype=self.psdType
|
||||
)
|
||||
elif self.psdType == "glyfast":
|
||||
(psd, par) = self.template_Gly_PSD_State_PL(
|
||||
nReceptors=n_rzones, psdtype=self.psdType
|
||||
)
|
||||
elif self.psdType == "glyGC":
|
||||
(psd, par) = self.template_Gly_PSD_State_GC(
|
||||
nReceptors=n_rzones, psdtype=self.psdType
|
||||
)
|
||||
elif self.psdType == "glya5":
|
||||
(psd, par) = self.template_Gly_PSD_State_Glya5(
|
||||
nReceptors=n_rzones, psdtype=self.psdType
|
||||
)
|
||||
elif self.psdType == "glyexp":
|
||||
(psd, par) = self.template_Gly_PSD_exp(
|
||||
nReceptors=n_rzones, psdtype=self.psdType
|
||||
)
|
||||
else:
|
||||
print("**PSDTYPE IS NOT RECOGNIZED: [%s]\n" % (self.psdType))
|
||||
exit()
|
||||
if debug:
|
||||
print("pre_sec: ", pre_sec)
|
||||
|
||||
# Connect terminal to psd (or cleft)
|
||||
self._cleft_netcons = []
|
||||
for k in range(0, n_rzones):
|
||||
pre_sec.push()
|
||||
netcon = h.NetCon(relzone._ref_XMTR[k], clefts[k], 0.1, 0.0, 1.0)
|
||||
self._cleft_netcons.append(netcon)
|
||||
h.pop_section()
|
||||
|
||||
# set cleft transmitter kinetic parameters
|
||||
for pname, pval in params.items():
|
||||
setattr(clefts[k], pname, pval)
|
||||
|
||||
h.setpointer(
|
||||
clefts[k]._ref_CXmtr, "XMTR", psd[k]
|
||||
) # connect transmitter release to the PSD
|
||||
|
||||
v = 1.0 + gvar * np.random.standard_normal()
|
||||
psd[k].gmax = (
|
||||
gmax * v
|
||||
) # add a little variability - gvar is CV of amplitudes
|
||||
# print 'GLY psd %s %d gmax=%f' % (self.psdType, k, gmax)
|
||||
psd[k].Erev = eRev # set the reversal potential
|
||||
|
||||
par = list(par)
|
||||
|
||||
if message is not None:
|
||||
print(message)
|
||||
|
||||
self.all_psd = psd
|
||||
self.clefts = clefts
|
||||
self.par = par
|
||||
|
||||
# the following templates are a bit more complicated.
|
||||
# The parameter names as defined in the model are returned
|
||||
# but also those that are involved in the forward binding reactions are
|
||||
# listed separately - this is to allow us to run curve fits that adjust
|
||||
# only a subset of the parameters a time - e.g., the rising phase, then
|
||||
# the falling phase with the rising phase fixed.
|
||||
# the dictionary selection is made by selectpars in glycine_fit.py.
|
||||
#
|
||||
|
||||
def template_Gly_PSD_exp(
|
||||
self, debug=False, nReceptors=2, cellname=None, message=None, loc=0.5
|
||||
):
|
||||
"""
|
||||
Template to build simple glycinergic exp-style PSD
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nReceptors : int, default=2
|
||||
number of sites to implement
|
||||
loc : float, default=0.5
|
||||
Position on the postsynaptic section to insert the mechanism, from [0..1].
|
||||
|
||||
Unused parameters:
|
||||
cellname, debug, message.
|
||||
|
||||
"""
|
||||
|
||||
sec = self.section
|
||||
psd = []
|
||||
sec.push()
|
||||
for k in range(0, nReceptors):
|
||||
psd.append(h.GLY2(loc, sec))
|
||||
h.pop_section()
|
||||
par = ["alpha", "beta"]
|
||||
p = []
|
||||
for n in par:
|
||||
p.append(eval("psd[0]." + n)) # get default values from the mod file
|
||||
return (psd, par, p)
|
||||
|
||||
def template_Gly_PSD_State_Glya5(
|
||||
self, debug=False, nReceptors=2, psdtype=None, message=None, loc=0.5
|
||||
):
|
||||
"""
|
||||
Template to build PSD using state model of glycine receptors, model glya5.mod
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nReceptors : int, default=2
|
||||
number of sites to implement
|
||||
loc : float, default=0.5
|
||||
Position on the postsynaptic section to insert the mechanism, from [0..1].
|
||||
|
||||
Unused parameters:
|
||||
cellname, debug, message, psdtype.
|
||||
|
||||
"""
|
||||
sec = self.section
|
||||
psd = []
|
||||
sec.push()
|
||||
for k in range(0, nReceptors):
|
||||
psd.append(h.GLYa5(loc, sec))
|
||||
h.pop_section()
|
||||
par = {
|
||||
"kf1": ("r", psd[0].kf1), # retreive values in the MOD file
|
||||
"kf2": ("r", psd[0].kf2),
|
||||
"kb1": ("r", psd[0].kb1),
|
||||
"kb2": ("r", psd[0].kb2),
|
||||
"a1": ("f", psd[0].a1),
|
||||
"b1": ("f", psd[0].b1),
|
||||
"a2": ("f", psd[0].a2),
|
||||
"b2": ("f", psd[0].b2),
|
||||
}
|
||||
return (psd, par)
|
||||
|
||||
def template_Gly_PSD_State_Gly6S(
|
||||
self, debug=False, nReceptors=2, psdtype=None, message=None, loc=0.5
|
||||
):
|
||||
"""
|
||||
Template to build PSD using state model of glycine receptors, model gly6s.mod
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nReceptors : int, default=2
|
||||
number of sites to implement
|
||||
loc : float, default=0.5
|
||||
Position on the postsynaptic section to insert the mechanism, from [0..1].
|
||||
psdtype : str, default=None
|
||||
resets the psd type to have slow kinetics if 'glyslow'. Any other string
|
||||
defaults to kinetics in the mod file.
|
||||
|
||||
Unused parameters:
|
||||
cellname, debug, message.
|
||||
|
||||
"""
|
||||
sec = self.section
|
||||
psd = []
|
||||
sec.push()
|
||||
for k in range(0, nReceptors):
|
||||
psd.append(
|
||||
h.Gly6S(loc, sec)
|
||||
) # simple using Trussell model 6 states with desens
|
||||
if debug:
|
||||
print("Gly6S psdtype: ", psdtype)
|
||||
if (
|
||||
psdtype == "glyslow"
|
||||
): # fit on 8 March 2010, error = 0.164, max open: 0.155
|
||||
psd[-1].Rd = 1.177999
|
||||
psd[-1].Rr = 0.000005
|
||||
psd[-1].Rb = 0.009403
|
||||
psd[-1].Ru2 = 0.000086
|
||||
psd[-1].Ro1 = 0.187858
|
||||
psd[-1].Ro2 = 1.064426
|
||||
psd[-1].Ru1 = 0.028696
|
||||
psd[-1].Rc1 = 0.103625
|
||||
psd[-1].Rc2 = 1.730578
|
||||
h.pop_section()
|
||||
par = {
|
||||
"Rb": ("n", psd[0].Rb), # retrive values in the MOD file
|
||||
"Ru1": ("r", psd[0].Ru1),
|
||||
"Ru2": ("r", psd[0].Ru2),
|
||||
"Rd": ("f", psd[0].Rd),
|
||||
"Rr": ("f", psd[0].Rr),
|
||||
"Ro1": ("f", psd[0].Ro1),
|
||||
"Ro2": ("r", psd[0].Ro2),
|
||||
"Rc1": ("f", psd[0].Rc1),
|
||||
"Rc2": ("r", psd[0].Rc2),
|
||||
}
|
||||
return (psd, par)
|
||||
|
||||
def template_Gly_PSD_State_PL(
|
||||
self,
|
||||
debug=False,
|
||||
nReceptors=2,
|
||||
cellname=None,
|
||||
psdtype=None,
|
||||
message=None,
|
||||
loc=0.5,
|
||||
):
|
||||
"""
|
||||
Template to build PSD using state model of glycine receptors, model glypl.mod
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nReceptors : int, default=2
|
||||
number of sites to implement
|
||||
loc : float, default=0.5
|
||||
Position on the postsynaptic section to insert the mechanism, from [0..1].
|
||||
psdtype : str, default=None
|
||||
resets the psd type to have slow kinetics if 'glyslow'.
|
||||
'glyfast' forces fast kinetics.
|
||||
Any other string defaults to the default kinetics in the mod file.
|
||||
|
||||
Unused parameters:
|
||||
cellname, debug, message,.
|
||||
|
||||
"""
|
||||
sec = self.section
|
||||
psd = []
|
||||
sec.push()
|
||||
for k in range(0, nReceptors):
|
||||
psd.append(h.GLYaPL(loc, sec)) # simple dextesche glycine receptors
|
||||
if debug:
|
||||
print("PL psdtype: ", psdtype)
|
||||
if psdtype == "glyslow":
|
||||
psd[-1].a1 = 0.000451
|
||||
psd[-1].a2 = 0.220
|
||||
psd[-1].b1 = 13.27
|
||||
psd[-1].b2 = 6.845
|
||||
psd[-1].kon = 0.00555
|
||||
psd[-1].koff = 2.256
|
||||
psd[-1].r = 1.060
|
||||
psd[-1].d = 55.03
|
||||
if (
|
||||
psdtype == "glyfast"
|
||||
): # fit from 3/5/2010. error = 0.174 maxopen = 0.0385
|
||||
psd[-1].a1 = 1.000476
|
||||
psd[-1].a2 = 0.137903
|
||||
psd[-1].b1 = 1.700306
|
||||
psd[-1].koff = 13.143132
|
||||
psd[-1].kon = 0.038634
|
||||
psd[-1].r = 0.842504
|
||||
psd[-1].b2 = 8.051435
|
||||
psd[-1].d = 12.821820
|
||||
h.pop_section()
|
||||
par = {
|
||||
"kon": ("r", psd[0].kon), # retrive values in the MOD file
|
||||
"koff": ("r", psd[0].koff),
|
||||
"a1": ("r", psd[0].a1),
|
||||
"b1": ("r", psd[0].b1),
|
||||
"a2": ("f", psd[0].a2),
|
||||
"b2": ("f", psd[0].b2),
|
||||
"r": ("f", psd[0].r),
|
||||
"d": ("f", psd[0].d),
|
||||
}
|
||||
return (psd, par)
|
||||
|
||||
def template_Gly_PSD_State_GC(
|
||||
self, debug=False, nReceptors=2, psdtype=None, message=None, loc=0.5
|
||||
):
|
||||
"""
|
||||
Template to build PSD using state model of glycine receptors, model glyaGC.mod
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nReceptors : int, default=2
|
||||
number of sites to implement
|
||||
loc : float, default=0.5
|
||||
Position on the postsynaptic section to insert the mechanism, from [0..1].
|
||||
psdtype : str, default=None
|
||||
resets the psd type to have slow kinetics if 'glyslow'. Any other string
|
||||
defaults to predefined kinetics in the mod file.
|
||||
|
||||
Unused parameters:
|
||||
cellname, debug, message, psdtype.
|
||||
|
||||
"""
|
||||
sec = self.section
|
||||
psd = []
|
||||
sec.push()
|
||||
for k in range(0, nReceptors):
|
||||
psd.append(h.GLYaGC(loc, sec)) # simple Dextesche glycine receptors
|
||||
if psdtype == "glyslow":
|
||||
psd[-1].k1 = 12.81 # (/uM /ms) : binding
|
||||
psd[-1].km1 = 0.0087 # (/ms) : unbinding
|
||||
psd[-1].a1 = 0.0195 # (/ms) : opening
|
||||
psd[-1].b1 = 1.138 # (/ms) : closing
|
||||
psd[-1].r1 = 6.13 # (/ms) : desense 1
|
||||
psd[-1].d1 = 0.000462 # (/ms) : return from d1
|
||||
psd[-1].r2 = 0.731 # (/ms) : return from deep state
|
||||
psd[-1].d2 = 1.65 # (/ms) : going to deep state
|
||||
psd[-1].r3 = 3.83 # (/ms) : return from deep state
|
||||
psd[-1].d3 = 1.806 # (/ms) : going to deep state
|
||||
psd[-1].rd = 1.04 # (/ms)
|
||||
psd[-1].dd = 1.004 # (/ms)
|
||||
h.pop_section()
|
||||
par = {
|
||||
"k1": ("r", psd[0].k1), # retrive values in the MOD file
|
||||
"km1": ("r", psd[0].km1),
|
||||
"a1": ("r", psd[0].a1),
|
||||
"b1": ("r", psd[0].b1),
|
||||
"r1": ("f", psd[0].r1),
|
||||
"d1": ("f", psd[0].d1),
|
||||
"r2": ("f", psd[0].r2),
|
||||
"d2": ("f", psd[0].d2),
|
||||
"r3": ("f", psd[0].r3),
|
||||
"d3": ("f", psd[0].d3),
|
||||
"rd": ("f", psd[0].rd),
|
||||
"dd": ("f", psd[0].dd),
|
||||
}
|
||||
return (psd, par)
|
||||
41
cnmodel/synapses/psd.py
Normal file
41
cnmodel/synapses/psd.py
Normal file
@@ -0,0 +1,41 @@
|
||||
class PSD(object):
|
||||
"""
|
||||
Base class for postsynaptic density mechanisms, possibly including cleft.
|
||||
May accept either NetCon or pointer inputs from a Terminal, and directly
|
||||
modifies the membrane potential and/or ion concentrations of the
|
||||
postsynaptic cell.
|
||||
"""
|
||||
|
||||
def __init__(self, section, terminal):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
section : :obj:`NEURON section`
|
||||
Set the section in the postsynaptic cell that the terminal is attached to.
|
||||
|
||||
terminal : :obj:`Synapse`
|
||||
|
||||
|
||||
"""
|
||||
self._section = section
|
||||
self._terminal = terminal
|
||||
|
||||
@property
|
||||
def section(self):
|
||||
""" The cell section this PSD is attached to.
|
||||
"""
|
||||
return self._section
|
||||
|
||||
@property
|
||||
def cell(self):
|
||||
""" The cell this PSD is attached to.
|
||||
"""
|
||||
from ..cells import Cell
|
||||
|
||||
return Cell.from_section(self.section)
|
||||
|
||||
@property
|
||||
def terminal(self):
|
||||
""" The presynaptic terminal connected to this PSD.
|
||||
"""
|
||||
return self._terminal
|
||||
52
cnmodel/synapses/simple_terminal.py
Normal file
52
cnmodel/synapses/simple_terminal.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from neuron import h
|
||||
|
||||
from .terminal import Terminal
|
||||
|
||||
|
||||
class SimpleTerminal(Terminal):
|
||||
"""
|
||||
Simple terminal using netcon.
|
||||
"""
|
||||
|
||||
def __init__(self, pre_sec, target_cell, spike_source=None, loc=0.5):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
pre_sec : :obj: `NEURON Section`
|
||||
The presynaptic section that is monitored for spikes. The voltage
|
||||
in this section is monitored to trigger the postsynaptic conductance
|
||||
as the spike source
|
||||
spike_source : :obj: `NEURON Section`
|
||||
Overrides the pre_sec as the spike source for this terminal.
|
||||
terminal : :obj: `Synapse Terminal`
|
||||
The presynaptic Terminal instance
|
||||
loc : float, default=0.5
|
||||
Position on the postsynaptic section to insert the mechanism, from [0..1].
|
||||
"""
|
||||
|
||||
Terminal.__init__(self, pre_sec)
|
||||
if spike_source is None:
|
||||
spike_source = pre_sec(loc)._ref_v
|
||||
self.spike_source = spike_source
|
||||
self.pre_sec = pre_sec
|
||||
|
||||
def connect(self, post, weight):
|
||||
"""
|
||||
Connect this terminal to a postsynaptic cell section
|
||||
The synaptic delay is 0.5 msec, and the presynaptic
|
||||
action potential threshold is -20 mV.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
post : :obj: `NEURON Section`
|
||||
|
||||
weight : float
|
||||
Strength of the connection
|
||||
|
||||
"""
|
||||
thresh = -20
|
||||
delay = 0.5
|
||||
self.netcon = h.NetCon(
|
||||
self.spike_source, post, thresh, delay, weight, sec=self.pre_sec
|
||||
)
|
||||
self.netcon.weight[0] = weight
|
||||
393
cnmodel/synapses/stochastic_terminal.py
Normal file
393
cnmodel/synapses/stochastic_terminal.py
Normal file
@@ -0,0 +1,393 @@
|
||||
from __future__ import print_function
|
||||
from neuron import h
|
||||
|
||||
from .terminal import Terminal
|
||||
from ..util import random_seed
|
||||
|
||||
# utility class to create parameter lists...
|
||||
# create like: p = Params(abc=2.0, defg = 3.0, lunch='sandwich')
|
||||
# reference like p.abc, p.defg, etc.
|
||||
class Params(object):
|
||||
def __init__(self, **kwds):
|
||||
self.__dict__.update(kwds)
|
||||
|
||||
|
||||
class StochasticTerminal(Terminal):
|
||||
"""
|
||||
Axon terminal with multi-site sctochastic release mechanism.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
pre_sec,
|
||||
target_cell,
|
||||
nzones=1,
|
||||
multisite=True,
|
||||
message=None,
|
||||
type="lognormal",
|
||||
identifier=0,
|
||||
stochastic_pars=None,
|
||||
calcium_pars=None,
|
||||
delay=0,
|
||||
debug=False,
|
||||
select=None,
|
||||
spike_source=None,
|
||||
dep_flag=1,
|
||||
):
|
||||
"""
|
||||
This routine creates a (potentially) multisite synapse using a NEURON mod file with:
|
||||
- A MultiSiteSynapse release mechanism that includes stochastic release, with a lognormal
|
||||
release latency distribution. The Facilitation and Depression of release are governed
|
||||
by parameters obtaine from fitting the Dittman-Kreitzer-Regher (DKR) model (J Neurosci. 2000 Feb 15;20(4):1374-85.)
|
||||
to experimental data at various
|
||||
frequencies.
|
||||
- A "cleft" mechanism (models diffusion of transmitter). Note that the cleft is inserted as part of the
|
||||
presynaptic section, but is not connected to the postsynaptic side yet.
|
||||
|
||||
Each release site is stochastically independent, but all sites within a terminal are drive by the
|
||||
same presynaptic action potentials.
|
||||
|
||||
Turning off the depression and facilitation in the kinetic portion of the model substantially decreases
|
||||
the time the terminal mechanism takes to run.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
pre_sec : :obj:`section`
|
||||
The NEURON section where the synaptic mechanisms should be inserted.
|
||||
target_cell : :obj:`Cell`
|
||||
The target cell object that the synapse will innervate.
|
||||
nzones : int
|
||||
The number of activate zones to insert into the section.
|
||||
multisite : bool, default: True
|
||||
A flag that determines whether the terminal actually creates multiple
|
||||
release zones (True) or just creates a single release zone that
|
||||
varies its amplitude based on the depression/facilitation state.
|
||||
message : str
|
||||
A message to when instantiating (mostly for verification of code flow).
|
||||
type: str (default: 'lognormal')
|
||||
'lognormal' sets the release event latency distribution to use a lognormal function. Currently,
|
||||
no other function is supported.
|
||||
identifier : int (default: 0)
|
||||
An identifier to associate with these release sites so we can find them later.
|
||||
stochastic_pars : dict (default: None)
|
||||
A dictionary of parameters (Param class) used to specifiy the stochastic behavior of this site,
|
||||
including release latency, stdev, and lognormal distribution paramaters
|
||||
calcium_pars : dict (default: None)
|
||||
A dictionary of parameters (Param class) to determine the calcium channels in this section.
|
||||
If None, then no calcium channels are inserted; otherwise, a P-type calcium conductance and a dynamic
|
||||
mechanism are inserted, and their conductance is set.
|
||||
delay : float (default: 0)
|
||||
Delay time in msec from action potential until transmitter release for this terminal.
|
||||
debug : bool (default: False)
|
||||
Flag to print stuff out while debugging.
|
||||
spike_source : :obj:`section` (default: None)
|
||||
The input spike source to use in net con - default is to use pre_sec when set to None.
|
||||
dep_flag : int (default: 1)
|
||||
Set to 1 for depression mechanism (slows computation), 0 to turn off the depression calculations
|
||||
|
||||
Returns
|
||||
-------
|
||||
list
|
||||
the list contains the terminal, the relsites, and the list of cleft mechanisms:
|
||||
|
||||
- terminal: this is the pointer to the terminal section that was inserted (same as pre_sec if it was
|
||||
specified)
|
||||
- relsite: a list of the nzones release sites that were created
|
||||
- cleft: a list of the nzones cleft mechanisms that were created.
|
||||
|
||||
"""
|
||||
Terminal.__init__(self, pre_sec)
|
||||
|
||||
# set parameter control for the stochastic release of vesicles...
|
||||
# this structure is passed to stochastic synapses, and replaces several variables
|
||||
# that were previously defined in the call to that function.
|
||||
|
||||
thresh = -30 # mV - AP detection on the presynaptic side.
|
||||
|
||||
ANTerminals_Latency = 0.5 # latency
|
||||
vPars = Params(
|
||||
LN_Flag=1,
|
||||
LN_t0=10.0,
|
||||
LN_A0=0.05,
|
||||
LN_tau=35,
|
||||
LN_std=0.05,
|
||||
Lat_Flag=1,
|
||||
Lat_t0=10.0,
|
||||
Lat_A0=0.140,
|
||||
Lat_tau=21.5,
|
||||
latency=ANTerminals_Latency,
|
||||
)
|
||||
# NOTE: stochastic_pars must define parameters used by multisite, including:
|
||||
# .delay is the netcon delay between the presynaptic AP and the start of release events
|
||||
# .Latency is the latency to the mean release event... this could be confusing.
|
||||
|
||||
if stochastic_pars is None:
|
||||
stochastic_pars = vPars
|
||||
|
||||
message = (
|
||||
" >> creating terminal with %d release zones using lognormal release latencies (coh4)"
|
||||
% nzones
|
||||
)
|
||||
if debug:
|
||||
print(message)
|
||||
terminal = pre_sec
|
||||
# terminal.push()
|
||||
if calcium_pars is not None:
|
||||
terminal.insert("cap") # insert calcium channel density
|
||||
terminal().cap.pcabar = calcium_pars.Ca_gbar
|
||||
terminal.insert("cad")
|
||||
|
||||
# Create point process to simulate multiple independent release zones.
|
||||
relsite = h.MultiSiteSynapse(0.5, sec=terminal)
|
||||
relsite.nZones = nzones
|
||||
if multisite:
|
||||
relsite.multisite = 1
|
||||
relsite.rseed = random_seed.current_seed() # use global random seed
|
||||
relsite.latency = stochastic_pars.latency
|
||||
relsite.latstd = stochastic_pars.LN_std
|
||||
self.n_rzones = nzones
|
||||
else:
|
||||
relsite.multisite = 0
|
||||
self.release_rng = h.Random(random_seed.current_seed())
|
||||
self.release_rng.uniform(0, 1)
|
||||
relsite.setUniformRNG(self.release_rng)
|
||||
self.n_rzones = 1
|
||||
|
||||
relsite.Dep_Flag = dep_flag # control synaptic dynamics
|
||||
if debug is True:
|
||||
relsite.debug = 1
|
||||
relsite.Identifier = identifier
|
||||
# if type == 'gamma':
|
||||
# gd = gamma.rvs(2, size=10000)/2.0 # get a sample of 10000 events with a gamma dist of 2, set to mean of 1.0
|
||||
# if relsite.latstd > 0.0:
|
||||
# gds = relsite.latency+std*(gd-1.0)/gd.std() # scale standard deviation
|
||||
# else:
|
||||
# gds = relsite.latency*np.ones((10000,1))
|
||||
# if type == 'lognormal':
|
||||
# if std > 0.0:
|
||||
# gds = lognormal(mean=0, sigma=relsite.latstd, size=10000)
|
||||
# else:
|
||||
# gds = np.zeros((10000, 1))
|
||||
# use the variable latency mode of COH4. And, it is lognormal no matter what.
|
||||
# the parameters are defined in COH4.mod as follows
|
||||
# Time course of latency shift in release during repetitive stimulation
|
||||
# Lat_Flag = 0 (1) : 0 means fixed latency, 1 means lognormal distribution
|
||||
# Lat_t0 = 0.0 (ms) : minimum time since simulation start before changes in latency are calculated
|
||||
# Lat_A0 = 0.0 (ms) : size of latency shift from t0 to infinity
|
||||
# Lat_tau = 100.0 (ms) : rate of change of latency shift (from fit of a+b(1-exp(-t/tau)))
|
||||
# : Statistical control of log-normal release shape over time during repetive stimulation
|
||||
# LN_Flag = 0 (1) : 0 means fixed values for all time
|
||||
# LN_t0 = 0.0 (ms) : : minimum time since simulation start before changes in distribution are calculated
|
||||
# LN_A0 = 0.0 (ms) : size of change in sigma from t0 to infinity
|
||||
# LN_tau = 100.0 (ms) : rate of change of sigma over time (from fit of a+b*(1-exp(-t/tau)))
|
||||
|
||||
relsite.LN_Flag = (
|
||||
stochastic_pars.LN_Flag
|
||||
) # enable use of lognormal release latency
|
||||
relsite.LN_t0 = stochastic_pars.LN_t0
|
||||
relsite.LN_A0 = stochastic_pars.LN_A0
|
||||
relsite.LN_tau = stochastic_pars.LN_tau
|
||||
relsite.Lat_Flag = stochastic_pars.Lat_Flag
|
||||
relsite.Lat_t0 = stochastic_pars.Lat_t0
|
||||
relsite.Lat_A0 = stochastic_pars.Lat_A0
|
||||
relsite.Lat_tau = stochastic_pars.Lat_tau
|
||||
# mpl.figure(2)
|
||||
|
||||
h.pop_section()
|
||||
self.relsite = relsite
|
||||
|
||||
if spike_source is None:
|
||||
spike_source = pre_sec(0.5)._ref_v
|
||||
|
||||
self.netcon = h.NetCon(spike_source, relsite, thresh, delay, 1.0, sec=pre_sec)
|
||||
self.netcon.weight[0] = 1
|
||||
self.netcon.threshold = -30.0
|
||||
|
||||
self.setPsdType(target_cell, select)
|
||||
|
||||
def setPsdType(self, target_cell, select=None):
|
||||
"""
|
||||
Assign a postsynpatic density type - selection of receptors to be
|
||||
associated with the presynaptic terminal.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
target_cell : :obj:`NEURON section`
|
||||
Define the target cell so that the correct PSD is inserted
|
||||
|
||||
select : str
|
||||
Not used in current implementation.
|
||||
|
||||
"""
|
||||
# TODO: must resurrect this for inhibitory synapses.
|
||||
# (and move constants out to their respective synapse locations)
|
||||
# elif psdtype.startswith('gly'):
|
||||
# self.setDF(target_cell, 'ipsc', select) # set the parameters for release
|
||||
self.setDF(target_cell, "epsc") # set the parameters for release
|
||||
|
||||
################################################################################
|
||||
# The following routines set the synapse dynamics, based on measurements and fit
|
||||
# to the DKR model.
|
||||
################################################################################
|
||||
|
||||
def setDF(self, target_cell, synapsetype, select=None):
|
||||
"""
|
||||
Set the facilitation/depression parameters for the multisite release model.
|
||||
The parameters used here were obtained from an optimized fit of the DKR
|
||||
model to stimulus and recovery data for the auditory nerve synapses onto bushy
|
||||
and T-stellate cells at 100, 200 and 300 Hz (simultaneous fitting), for times out to about
|
||||
0.5 - 1.0 second. Data were collected by Dr. Ruili Xie and Dr. Yong Wang.
|
||||
Fitting by Paul Manis.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
target_cell : :obj:`NEURON section`
|
||||
Define the target cell so that the correct release kinetics are used
|
||||
|
||||
synapsetype : str
|
||||
String defining the type of synapse: 'ipsc' or 'epsc'
|
||||
|
||||
select : str (default: None)
|
||||
Select kinetcs from a particular example cell.
|
||||
|
||||
"""
|
||||
from .. import cells
|
||||
|
||||
if isinstance(target_cell, cells.Bushy):
|
||||
if synapsetype == "ipsc":
|
||||
if select is None:
|
||||
self.bushy_ipsc_average()
|
||||
else:
|
||||
self.bushy_ipsc_single(select=select)
|
||||
elif isinstance(target_cell, cells.TStellate):
|
||||
if synapsetype == "ipsc":
|
||||
self.stellate_ipsc()
|
||||
|
||||
def set_params(self, **params):
|
||||
"""Set arbitrary parameters on the release mechanism.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
\**params : dict
|
||||
dictionary of parameters to set on the release mechanism.
|
||||
|
||||
"""
|
||||
for k, v in params.items():
|
||||
setattr(self.relsite, k, v)
|
||||
|
||||
def stellate_ipsc(self):
|
||||
""" Facilitation/Depression parameters for DKR model for IPSCs onto stellate cells.
|
||||
IPSCs were derived from stimulation of the dorsal cochlear nucleus, and so represent
|
||||
the glycinergic synapses from tuberculoventral neurons.
|
||||
Data is average of 3 cells studied with recovery curves and individually fit, at 100 Hz.
|
||||
"""
|
||||
self.relsite.F = 0.23047
|
||||
self.relsite.k0 = 1.23636
|
||||
self.relsite.kmax = 45.34474
|
||||
self.relsite.taud = 98.09
|
||||
self.relsite.kd = 0.01183
|
||||
self.relsite.taus = 17614.50
|
||||
self.relsite.ks = 17.88618
|
||||
self.relsite.kf = 19.11424
|
||||
self.relsite.tauf = 32.28
|
||||
self.relsite.dD = 2.52072
|
||||
self.relsite.dF = 2.33317
|
||||
self.relsite.glu = 3.06948
|
||||
|
||||
def bushy_ipsc_average(self):
|
||||
""" Facilitation/Depression parameters for DKR model for IPSCs onto bushy cells.
|
||||
IPSCs were derived from stimulation of the dorsal cochlear nucleus, and so represent
|
||||
the glycinergic synapses from tuberculoventral neurons.
|
||||
Data for the kinetcs are the average of 16 bushy cells.
|
||||
The individual fits were compiled, and an average computed for just the 100 Hz data
|
||||
across the individual fits. This average was then fit to the DKR model
|
||||
(also see Matthew Xu-Friedman's papers).
|
||||
The individual cells show a great deal of variability, from straight depression, to
|
||||
mixed depression/facilitaiton, to facilation alone. This set of parameters generates
|
||||
a weak facilitation followed by depression back to baseline.
|
||||
|
||||
There are other data sets in the source that are commented out.
|
||||
"""
|
||||
# print( "USING average kinetics for Bushy IPSCs")
|
||||
|
||||
# average of 16cells for 100 Hz (to model); no recovery.
|
||||
self.relsite.F = 0.18521
|
||||
self.relsite.k0 = 2.29700
|
||||
self.relsite.kmax = 27.6667
|
||||
self.relsite.taud = 0.12366
|
||||
self.relsite.kd = 0.12272
|
||||
self.relsite.taus = 9.59624
|
||||
self.relsite.ks = 8.854469
|
||||
self.relsite.kf = 5.70771
|
||||
self.relsite.tauf = 0.37752
|
||||
self.relsite.dD = 4.00335
|
||||
self.relsite.dF = 0.72605
|
||||
self.relsite.glu = 5.61985
|
||||
|
||||
def bushy_ipsc_single(self, select=None):
|
||||
"""
|
||||
Facilitation/Depression parameters for DKR model for IPSCs onto 3 individual bushy cells.
|
||||
IPSCs were derived from stimulation of the dorsal cochlear nucleus, and so represent
|
||||
the glycinergic synapses from tuberculoventral neurons.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
select : int, default=None
|
||||
select which cell's measured kinetics will be used:
|
||||
|
||||
0: Use average
|
||||
1: use data from 30aug08f
|
||||
2: select = 2, use data from 30aug08h
|
||||
3: select = 3, use data from 31aug08b (single cell, clean dataset)
|
||||
|
||||
"""
|
||||
# print ("Using bushy ipsc")
|
||||
|
||||
if select is None or select > 4 or select <= 0:
|
||||
self.bushy_ipsc_average()
|
||||
return
|
||||
|
||||
if select is 1: # 30aug08f
|
||||
# print ("using 30aug08f ipsc")
|
||||
self.relsite.F = 0.221818
|
||||
self.relsite.k0 = 0.003636364
|
||||
self.relsite.kmax = 0.077562107
|
||||
self.relsite.taud = 0.300000
|
||||
self.relsite.kd = 1.112554
|
||||
self.relsite.taus = 3.500000
|
||||
self.relsite.ks = 0.600000
|
||||
self.relsite.kf = 3.730452
|
||||
self.relsite.tauf = 0.592129
|
||||
self.relsite.dD = 0.755537
|
||||
self.relsite.dF = 2.931578
|
||||
self.relsite.glu = 1.000000
|
||||
|
||||
if select is 2: # 30aug08h
|
||||
# print ("using 30aug08H ipsc")
|
||||
self.relsite.F = 0.239404
|
||||
self.relsite.k0 = 3.636364 / 1000.0
|
||||
self.relsite.kmax = 16.725479 / 1000.0
|
||||
self.relsite.taud = 0.137832
|
||||
self.relsite.kd = 0.000900
|
||||
self.relsite.taus = 3.500000
|
||||
self.relsite.ks = 0.600000
|
||||
self.relsite.kf = 4.311995
|
||||
self.relsite.tauf = 0.014630
|
||||
self.relsite.dD = 3.326148
|
||||
self.relsite.dF = 0.725512
|
||||
self.relsite.glu = 1.000000
|
||||
|
||||
if select is 3:
|
||||
# print ("using IPSC#3 ")
|
||||
self.relsite.F = 0.29594
|
||||
self.relsite.k0 = 0.44388 / 1000.0
|
||||
self.relsite.kmax = 15.11385 / 1000.0
|
||||
self.relsite.taud = 0.00260
|
||||
self.relsite.kd = 0.00090
|
||||
self.relsite.taus = 11.40577
|
||||
self.relsite.ks = 27.98783
|
||||
self.relsite.kf = 30.00000
|
||||
self.relsite.tauf = 0.29853
|
||||
self.relsite.dD = 3.70000
|
||||
self.relsite.dF = 2.71163
|
||||
self.relsite.glu = 4.97494
|
||||
15
cnmodel/synapses/synapse.py
Normal file
15
cnmodel/synapses/synapse.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from .stochastic_terminal import StochasticTerminal
|
||||
from .psd import PSD
|
||||
|
||||
|
||||
class Synapse(object):
|
||||
"""Encapsulates a synaptic connection between two cells.
|
||||
|
||||
Instances of this class are created by calling `Cell.connect()`.
|
||||
"""
|
||||
|
||||
def __init__(self, pre_cell, pre_opts, post_cell, post_opts, type="multisite"):
|
||||
pre_opts["term_type"] = type
|
||||
post_opts["psd_type"] = type
|
||||
self.terminal = pre_cell.make_terminal(post_cell, **pre_opts)
|
||||
self.psd = post_cell.make_psd(self.terminal, **post_opts)
|
||||
32
cnmodel/synapses/terminal.py
Normal file
32
cnmodel/synapses/terminal.py
Normal file
@@ -0,0 +1,32 @@
|
||||
class Terminal(object):
|
||||
"""
|
||||
Base class for axon terminals. A terminal has a single postsynaptic
|
||||
neuron, but may have multiple release zones. It defines a release mechanism
|
||||
with a NetCon input (triggering from presynaptic voltage or calcium level)
|
||||
and either NetCon or pointer output for driving a PSD.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, section):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
section : :obj:`NEURON section`
|
||||
Set the section in the postsynaptic cell that the terminal is attached to.
|
||||
|
||||
"""
|
||||
self._section = section
|
||||
|
||||
@property
|
||||
def section(self):
|
||||
""" The cell section this terminal is attached to.
|
||||
"""
|
||||
return self._section
|
||||
|
||||
@property
|
||||
def cell(self):
|
||||
""" The cell this terminal is attached to.
|
||||
"""
|
||||
from ..cells import Cell
|
||||
|
||||
return Cell.from_section(self.section)
|
||||
3
cnmodel/synapses/tests/test_data/dstellate_bushy.pk
Normal file
3
cnmodel/synapses/tests/test_data/dstellate_bushy.pk
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:770319a9229c66e4796757854b0d1e341f5d376abf0284385360788c41c6d20b
|
||||
size 11836
|
||||
3
cnmodel/synapses/tests/test_data/dstellate_dstellate.pk
Normal file
3
cnmodel/synapses/tests/test_data/dstellate_dstellate.pk
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:83554699cefe547a22eb959c83cf9a86d62383d858a1b8d78716eae16b382e43
|
||||
size 6110
|
||||
3
cnmodel/synapses/tests/test_data/dstellate_tstellate.pk
Normal file
3
cnmodel/synapses/tests/test_data/dstellate_tstellate.pk
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c812143a8582d423c7fababd2060bbbaa064b5b767f576cd117685af207c944e
|
||||
size 11421
|
||||
3
cnmodel/synapses/tests/test_data/sgc_bushy.pk
Normal file
3
cnmodel/synapses/tests/test_data/sgc_bushy.pk
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:42d5eed880a498157400a9fdc442341e7e32c1ef1db8d398ac016e27fcbb6286
|
||||
size 42555
|
||||
3
cnmodel/synapses/tests/test_data/sgc_dstellate.pk
Normal file
3
cnmodel/synapses/tests/test_data/sgc_dstellate.pk
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6176f9cbf15f5f81d36a7cf64e0d9a72e0187a0d647642b838f72c0373a3349e
|
||||
size 8867
|
||||
3
cnmodel/synapses/tests/test_data/sgc_tstellate.pk
Normal file
3
cnmodel/synapses/tests/test_data/sgc_tstellate.pk
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e62835df05a9f859bbae3d48639bdb4456ca91a7ce62405f618e692494d5c92c
|
||||
size 10586
|
||||
190
cnmodel/synapses/tests/test_psd.py
Normal file
190
cnmodel/synapses/tests/test_psd.py
Normal file
@@ -0,0 +1,190 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
import numpy as np
|
||||
import pyqtgraph as pg
|
||||
import neuron
|
||||
|
||||
import cnmodel
|
||||
import cnmodel.cells as cells
|
||||
from cnmodel.protocols import SynapseTest
|
||||
from cnmodel.util import random_seed, reset
|
||||
from cnmodel import data
|
||||
|
||||
"""
|
||||
Check that sgc PSDs have correct AMPA and NMDA peak conductances / CV.
|
||||
"""
|
||||
|
||||
|
||||
def test_sgc_bushy_psd(plot=False):
|
||||
sgc_psd_test(cells.Bushy, seed=23572385, tstop=4.0, plot=plot)
|
||||
|
||||
|
||||
def test_sgc_tstellate_psd(plot=False):
|
||||
sgc_psd_test(cells.TStellate, seed=34754398, plot=plot)
|
||||
|
||||
|
||||
def test_sgc_dstellate_psd(plot=False):
|
||||
sgc_psd_test(cells.DStellate, seed=54743998, plot=plot, n_syn=50)
|
||||
|
||||
|
||||
def test_sgc_octopus_psd(plot=False):
|
||||
sgc_psd_test(cells.Octopus, seed=54743998, plot=plot, n_syn=50)
|
||||
|
||||
|
||||
def sgc_psd_test(cell_class, seed, plot=False, tstop=5.0, n_syn=20):
|
||||
"""
|
||||
Tests a multisite synapse from the SGC to a target cell.
|
||||
The values returned from an actual set of runs of the synapse are compared
|
||||
to the expected values in the synapses.py table. This is needed because
|
||||
the maximal open probability of the receptor models is not 1, so the maximal
|
||||
conductance per receptor needs to be adjusted empirically. If the measured current
|
||||
does not match the expected current, then we print a message with the expected value,
|
||||
and fail with an assert statment in the test.
|
||||
The measurement itself is made in measure_gmax().
|
||||
|
||||
Parameters
|
||||
----------
|
||||
cell_class : an instance of the cell class
|
||||
seed : int
|
||||
random number seed for the call
|
||||
plot : boolean (default False)
|
||||
plot request, passed to measure_gmax
|
||||
tstop : float (default 5.0 ms)
|
||||
duration of run for measurement of gmax. Needs to be long enough to find the
|
||||
maximum of the EPSC/IPSC.
|
||||
n_syn : int (default 20)
|
||||
number of synapses to instantiate for testing (to get an average value)
|
||||
|
||||
"""
|
||||
celltyp = cell_class.__name__.lower()
|
||||
|
||||
random_seed.set_seed(seed)
|
||||
reset(
|
||||
raiseError=False
|
||||
) # avoid failure because we cannot release NEURON objects completely.
|
||||
tsc = cell_class.create(ttx=True)
|
||||
(ampa_gmax, nmda_gmax, epsc_cv) = measure_gmax(
|
||||
tsc, n_syn=n_syn, tstop=tstop, plot=plot
|
||||
)
|
||||
exp_ampa_gmax = data.get(
|
||||
"sgc_synapse", species="mouse", post_type=celltyp, field="AMPA_gmax"
|
||||
)[0]
|
||||
exp_nmda_gmax = data.get(
|
||||
"sgc_synapse", species="mouse", post_type=celltyp, field="NMDA_gmax"
|
||||
)[0]
|
||||
exp_epsc_cv = data.get(
|
||||
"sgc_synapse", species="mouse", post_type=celltyp, field="EPSC_cv"
|
||||
)
|
||||
ampa_correct = np.allclose(exp_ampa_gmax, ampa_gmax)
|
||||
if not ampa_correct:
|
||||
AMPAR_gmax = data.get(
|
||||
"sgc_synapse", species="mouse", post_type=celltyp, field="AMPAR_gmax"
|
||||
)
|
||||
ratio = exp_ampa_gmax / ampa_gmax
|
||||
print(
|
||||
"AMPA Receptor conductance in model should be %.16f (table is %.16f)"
|
||||
% (AMPAR_gmax * ratio, AMPAR_gmax)
|
||||
)
|
||||
nmda_correct = np.allclose(exp_nmda_gmax, nmda_gmax)
|
||||
if not nmda_correct:
|
||||
NMDAR_gmax = data.get(
|
||||
"sgc_synapse", species="mouse", post_type=celltyp, field="NMDAR_gmax"
|
||||
)
|
||||
ratio = exp_nmda_gmax / nmda_gmax
|
||||
print("ratio: ", ratio, exp_nmda_gmax, nmda_gmax)
|
||||
print(
|
||||
"NMDA Receptor conductance in model should be %.16f (table is %.16f)"
|
||||
% (NMDAR_gmax * ratio, NMDAR_gmax)
|
||||
)
|
||||
cv_correct = abs(exp_epsc_cv / epsc_cv - 1.0) < 0.1
|
||||
print("cv_correct: ", cv_correct)
|
||||
if not cv_correct:
|
||||
ratio = exp_epsc_cv / epsc_cv
|
||||
print(
|
||||
"CV Receptor in synapses.py model should be %.6f (measured = %.6f; table = %.6f)"
|
||||
% (epsc_cv * ratio, epsc_cv, exp_epsc_cv)
|
||||
)
|
||||
print((abs(exp_epsc_cv / (epsc_cv * ratio) - 1.0) < 0.1))
|
||||
assert cv_correct
|
||||
assert ampa_correct and nmda_correct
|
||||
|
||||
|
||||
def measure_gmax(cell, n_syn=20, tstop=5.0, plot=False):
|
||||
sgc = cells.SGC.create()
|
||||
prot = SynapseTest()
|
||||
|
||||
# Connect 20 synapses and stimulate once each
|
||||
# Temp is 33 C and vm=+40 to match Cao & Oertel 2010
|
||||
prot.run(
|
||||
sgc.soma,
|
||||
cell.soma,
|
||||
n_synapses=n_syn,
|
||||
temp=33.0,
|
||||
dt=0.025,
|
||||
vclamp=40.0,
|
||||
tstop=tstop,
|
||||
stim_params={"NP": 1, "delay": 0.1},
|
||||
)
|
||||
|
||||
# For each synapse:
|
||||
# * Add up ampa and nmda conductances across all sites
|
||||
# (although SGC-TS synapses currently have only 1 site)
|
||||
# * Keep track of the maximum ampa and nmda conductance
|
||||
if plot:
|
||||
global plt
|
||||
plt = pg.plot()
|
||||
ampa_gmax = []
|
||||
nmda_gmax = []
|
||||
epsc_gmax = []
|
||||
for syn in prot.synapses:
|
||||
ampa = np.zeros_like(syn.psd.get_vector("ampa", "g"))
|
||||
nmda = ampa.copy()
|
||||
ampa_po = ampa.copy()
|
||||
for i in range(syn.psd.n_psd):
|
||||
|
||||
ampa += (
|
||||
syn.psd.get_vector("ampa", "g", i) * 1e-3
|
||||
) # convert pS from mechanism to nS
|
||||
nmda += syn.psd.get_vector("nmda", "g", i) * 1e-3
|
||||
if nmda[-1] - nmda[-2] > 0.001:
|
||||
raise Exception("Did not reach nmda gmax; need longer run.")
|
||||
amax = ampa.max()
|
||||
ampa_gmax.append(amax)
|
||||
nmda_gmax.append(nmda.max())
|
||||
epsc_gmax.append((ampa + nmda).max())
|
||||
tb = np.linspace(0.0, len(ampa) * prot.dt, len(ampa))
|
||||
if plot:
|
||||
plt.plot(tb, ampa, pen="g")
|
||||
plt.plot(tb, nmda, pen="y")
|
||||
return (
|
||||
np.mean(ampa_gmax),
|
||||
np.mean(nmda_gmax),
|
||||
np.std(epsc_gmax) / np.mean(epsc_gmax),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv[0]) > 1:
|
||||
testcell = sys.argv[1]
|
||||
if testcell not in ["bushy", "tstellate", "dstellate", "octopus", "all"]:
|
||||
print("PSD test for cell type %s is not yet supported." % testcell)
|
||||
exit(1)
|
||||
else:
|
||||
if testcell in ["bushy"]:
|
||||
test_sgc_bushy_psd(plot=True)
|
||||
if testcell in ["tstellate"]:
|
||||
test_sgc_tstellate_psd(plot=True)
|
||||
if testcell in ["dstellate"]:
|
||||
test_sgc_dstellate_psd(plot=True)
|
||||
if testcell in ["octopus"]:
|
||||
test_sgc_octopus_psd(plot=True)
|
||||
if testcell in ["all"]:
|
||||
test_sgc_bushy_psd(plot=True)
|
||||
test_sgc_tstellate_psd(plot=True)
|
||||
test_sgc_dstellate_psd(plot=True)
|
||||
test_sgc_octopus(plot=True)
|
||||
|
||||
# pg.show()
|
||||
if sys.flags.interactive == 0:
|
||||
pg.QtGui.QApplication.exec_()
|
||||
119
cnmodel/synapses/tests/test_synapses.py
Normal file
119
cnmodel/synapses/tests/test_synapses.py
Normal file
@@ -0,0 +1,119 @@
|
||||
"""
|
||||
Create presynaptic and postsynaptic neurons, automatically connect them with
|
||||
a synapse, stimulate the presynaptic cell, and analyze the resulting PSCs
|
||||
in the postsynaptic cell.
|
||||
"""
|
||||
import faulthandler
|
||||
|
||||
faulthandler.enable()
|
||||
import os, pickle, pprint
|
||||
import numpy as np
|
||||
import neuron
|
||||
|
||||
import cnmodel
|
||||
import cnmodel.cells as cells
|
||||
from cnmodel.util import UserTester
|
||||
from cnmodel.protocols import SynapseTest
|
||||
from cnmodel.util import reset
|
||||
|
||||
#
|
||||
# Synapse tests
|
||||
#
|
||||
def test_sgc_bushy():
|
||||
SynapseTester("sgc", "bushy")
|
||||
|
||||
|
||||
def test_sgc_tstellate():
|
||||
SynapseTester("sgc", "tstellate")
|
||||
|
||||
|
||||
def test_sgc_tstellate2(): # again to test RNG stability
|
||||
SynapseTester("sgc", "tstellate")
|
||||
|
||||
|
||||
def test_sgc_dstellate():
|
||||
SynapseTester("sgc", "dstellate")
|
||||
|
||||
|
||||
def test_dstellate_bushy():
|
||||
SynapseTester("dstellate", "bushy")
|
||||
|
||||
|
||||
def test_dstellate_tstellate():
|
||||
SynapseTester("dstellate", "tstellate")
|
||||
|
||||
|
||||
def test_dstellate_dstellate():
|
||||
SynapseTester("dstellate", "dstellate")
|
||||
|
||||
|
||||
#
|
||||
# Supporting functions
|
||||
#
|
||||
convergence = {
|
||||
"sgc": {"bushy": 3, "tstellate": 6, "dstellate": 10, "dstellate_eager": 10},
|
||||
"dstellate": {"bushy": 10, "tstellate": 15, "dstellate": 5},
|
||||
}
|
||||
|
||||
|
||||
def make_cell(typ):
|
||||
if typ == "sgc":
|
||||
cell = cells.SGC.create()
|
||||
elif typ == "tstellate":
|
||||
cell = cells.TStellate.create(debug=True, ttx=False)
|
||||
elif (
|
||||
typ == "dstellate"
|
||||
): # Type I-II Rothman model, similiar excitability (Xie/Manis, unpublished)
|
||||
cell = cells.DStellate.create(model="RM03", debug=True, ttx=False)
|
||||
elif typ == "dstellate_eager": # From Eager et al.
|
||||
cell = cells.DStellate.create(model="Eager", debug=True, ttx=False)
|
||||
elif typ == "bushy":
|
||||
cell = cells.Bushy.create(debug=True, ttx=False)
|
||||
else:
|
||||
raise ValueError("Unknown cell type '%s'" % typ)
|
||||
return cell
|
||||
|
||||
|
||||
class SynapseTester(UserTester):
|
||||
def __init__(self, pre, post):
|
||||
self.st = None
|
||||
UserTester.__init__(self, "%s_%s" % (pre, post), pre, post)
|
||||
|
||||
def run_test(self, pre, post):
|
||||
# Make sure no objects are left over from previous tests
|
||||
reset(raiseError=False)
|
||||
|
||||
# seed random generator using the name of this test
|
||||
seed = "%s_%s" % (pre, post)
|
||||
|
||||
pre_cell = make_cell(pre)
|
||||
post_cell = make_cell(post)
|
||||
|
||||
n_term = convergence.get(pre, {}).get(post, None)
|
||||
if n_term is None:
|
||||
n_term = 1
|
||||
st = SynapseTest()
|
||||
st.run(pre_cell.soma, post_cell.soma, n_term, seed=seed)
|
||||
if self.audit:
|
||||
st.show_result()
|
||||
|
||||
info = dict(
|
||||
rel_events=st.release_events(),
|
||||
rel_timings=st.release_timings(),
|
||||
open_prob=st.open_probability(),
|
||||
event_analysis=st.analyze_events(),
|
||||
)
|
||||
self.st = st
|
||||
|
||||
# import weakref
|
||||
# global last_syn
|
||||
# last_syn = weakref.ref(st.synapses[0].terminal.relsi)
|
||||
|
||||
return info
|
||||
|
||||
def assert_test_info(self, *args, **kwds):
|
||||
try:
|
||||
super(SynapseTester, self).assert_test_info(*args, **kwds)
|
||||
finally:
|
||||
if self.st is not None:
|
||||
self.st.hide()
|
||||
Reference in New Issue
Block a user