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