copying to personal repo

This commit is contained in:
Alan
2022-06-19 13:45:53 -05:00
commit bf2ffa7315
287 changed files with 54032 additions and 0 deletions

View 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

View 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
View 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
View 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
View 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

View 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

View 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

View 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)

View 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)

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:770319a9229c66e4796757854b0d1e341f5d376abf0284385360788c41c6d20b
size 11836

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:83554699cefe547a22eb959c83cf9a86d62383d858a1b8d78716eae16b382e43
size 6110

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c812143a8582d423c7fababd2060bbbaa064b5b767f576cd117685af207c944e
size 11421

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:42d5eed880a498157400a9fdc442341e7e32c1ef1db8d398ac016e27fcbb6286
size 42555

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6176f9cbf15f5f81d36a7cf64e0d9a72e0187a0d647642b838f72c0373a3349e
size 8867

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e62835df05a9f859bbae3d48639bdb4456ca91a7ce62405f618e692494d5c92c
size 10586

View 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_()

View 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()