model of DCN pyramidal neuron
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

468 lines
17 KiB

from __future__ import print_function
from neuron import h
from ..util import nstomho
from ..util import Params
import numpy as np
from .cell import Cell
from .. import synapses
from .. import an_model
from .. import data
__all__ = ["SGC", "SGC_TypeI", "DummySGC"]
class SGC(Cell):
type = "sgc"
@classmethod
def create(cls, model="I", species="mouse", **kwds):
if model == "dummy":
return DummySGC(**kwds)
elif model == "I":
return SGC_TypeI(species=species, **kwds)
else:
raise ValueError("SGC model %s is unknown", model)
def __init__(self, cf=None, sr=None):
Cell.__init__(self)
self._cf = cf
self._sr = sr
self.spike_source = None # used by DummySGC to connect VecStim to terminal
@property
def cf(self):
""" Center frequency
"""
return self._cf
@property
def sr(self):
""" Spontaneous rate group. 1=low, 2=mid, 3=high
"""
return self._sr
def make_terminal(self, post_cell, term_type, **kwds):
"""Create a StochasticTerminal and configure it according to the
postsynaptic cell type.
"""
pre_sec = self.soma
# Return a simple terminal unless a stochastic terminal was requested.
if term_type == "simple":
return synapses.SimpleTerminal(
pre_sec, post_cell, spike_source=self.spike_source, **kwds
)
elif term_type == "multisite":
n_rsites = data.get(
"sgc_synapse",
species="mouse",
post_type=post_cell.type,
field="n_rsites",
)
opts = {"nzones": n_rsites, "delay": 0, "dep_flag": 1}
opts.update(kwds)
# when created, depflag is set True (1) so that we compute the DKR D*F to get release
# this can be modified prior to the run by setting the terminal(s) so that dep_flag is 0
# (no DKR: constant release probability)
term = synapses.StochasticTerminal(
pre_sec, post_cell, spike_source=self.spike_source, **opts
)
kinetics = data.get(
"sgc_ampa_kinetics",
species="mouse",
post_type=post_cell.type,
field=["tau_g", "amp_g"],
)
term.set_params(**kinetics)
dynamics = data.get(
"sgc_release_dynamics",
species="mouse",
post_type=post_cell.type,
field=["F", "k0", "kmax", "kd", "kf", "taud", "tauf", "dD", "dF"],
)
term.set_params(**dynamics)
return term
else:
raise ValueError("Unsupported terminal type %s" % term_type)
class DummySGC(SGC):
""" SGC class with no cell body; this cell only replays a predetermined
spike train.
"""
def __init__(self, cf=None, sr=None, simulator=None):
"""
Parameters
----------
cf : float (default: None)
Required: the characteristic frequency for the SGC
sr : int (default None)
required : Selects the spontaneous rate group from the
Zilany et al (2010) model. 1 = LSR, 2 = MSR, 3 = HSR
simulator : 'cochlea' | 'matlab' | None (default None)
Sets the simulator interface that will be used. All models
currently use the Zilany et al. model, but the simulator can
be run though a Python-interface directly to the Matlab code
as publicy available, (simulator='matlab'), or can be run through
Rudnicki & Hemmert's Python interface to the simulator's C code
(simulator='cochlea').
"""
self._simulator = simulator
SGC.__init__(self, cf, sr)
self.vecstim = h.VecStim()
# this causes the terminal to receive events from the VecStim:
self.spike_source = self.vecstim
# just an empty section for holding the terminal
self.add_section(h.Section(), "soma")
self.status = {
"soma": True,
"axon": False,
"dendrites": False,
"pumps": False,
"na": None,
"species": None,
"modelType": "dummy",
"ttx": False,
"name": "DummysGC",
"morphology": None,
"decorator": None,
"temperature": None,
}
def set_spiketrain(self, times):
""" Set the times of spikes (in seconds) to be replayed by the cell.
"""
self._spiketrain = times
self._stvec = h.Vector(times)
self.vecstim.play(self._stvec)
def set_sound_stim(self, stim, seed, simulator=None):
""" Set the sound stimulus used to generate this cell's spike train.
"""
self._sound_stim = stim
spikes = self.generate_spiketrain(stim, seed, simulator)
self.set_spiketrain(spikes)
def generate_spiketrain(self, stim, seed, simulator=None):
if simulator is None:
simulator = self._simulator
spikes = an_model.get_spiketrain(
cf=self.cf, sr=self.sr, seed=seed, stim=stim, simulator=simulator
)
return spikes * 1000
class SGC_TypeI(SGC):
"""
Spiral ganglion cell model
"""
def __init__(
self,
morphology=None,
decorator=None,
nach=None,
ttx=False,
species="guineapig",
modelType="bm",
cf=None,
sr=None,
debug=False,
):
"""
Initialize a spiral ganglion Type I cell, based on a bushy cell model.
Modifications to the cell can be made by calling the methods below. These include
converting to a model with modified size and conductances (experimental), and
and changing the sodium channel conductances.
Parameters
----------
morphology : string (default: None)
a file name to read the cell morphology from. If a valid file is found, a cell is constructed
as a cable model from the hoc file.
If None (default), the only a point model is made, exactly according to RM03.
decorator : Python function (default: None)
decorator is a function that "decorates" the morphology with ion channels according
to a set of rules.
If None, a default set of channels aer inserted into the first soma section, and the
rest of the structure is "bare".
nach : string (default: 'na')
nach selects the type of sodium channel that will be used in the model. A channel mechanim
by that name must exist. The default is jsrna (Rothman et al., 1993)
ttx : Boolean (default: False)
If ttx is True, then the sodium channel conductance is set to 0 everywhere in the cell.
Currently, this is not implemented.
species: string (default 'guineapig')
species defines the channel density that will be inserted for different models. Note that
if a decorator function is specified, this argument is ignored.
modelType: string (default: None)
modelType specifies the type of the model that will be used. SGC model know about "a" (apical)
and "bm" (basal-middle) models, based on Liu et al., JARO, 2014.
modelType is passed to the decorator, or to species_scaling to adjust point models.
cf : float (default: None)
The CF for the auditory nerve fiber that this SGC represents.
sr : string (default: None)
The spontaneous rate group to which this fiber belongs. "LS", "MS", and "HS" are known values.
debug: boolean (default: False)
debug is a boolean flag. When set, there will be multiple printouts of progress and parameters.
Returns
-------
Nothing
"""
super(SGC_TypeI, self).__init__(cf=cf, sr=sr)
if modelType == None:
modelType = "bm" # modelTypes are: a (apical), bm (basal middle)
if nach == None:
nach = "jsrna"
self.status = {
"soma": True,
"axon": False,
"dendrites": False,
"pumps": False,
"na": nach,
"species": species,
"modelType": modelType,
"ttx": ttx,
"name": "SGC",
"morphology": morphology,
"decorator": decorator,
"temperature": None,
}
self.i_test_range = {
"pulse": [(-0.3, 0.3, 0.02), (-0.03, 0.0, 0.005)]
} # include finer range as well
self.vrange = [-75.0, -55.0]
if morphology is None:
"""
instantiate a basic soma-only ("point") model
"""
soma = h.Section(
name="SGC_Soma_%x" % id(self)
) # one compartment of about 29000 um2
soma.nseg = 1
self.add_section(soma, "soma")
else:
"""
instantiate a structured model with the morphology as specified by
the morphology file
"""
self.set_morphology(morphology_file=morphology)
# decorate the morphology with ion channels
if decorator is None: # basic model, only on the soma
self.mechanisms = [nach, "klt", "kht", "leak"]
if modelType == "a":
self.mechanisms.append("ihsgcApical")
elif modelType == "bm":
self.mechanisms.append("ihsgcBasalMiddle")
else:
raise ValueError("Type %s not known for SGC model" % modelType)
for mech in self.mechanisms:
self.soma.insert(mech)
self.soma.ek = self.e_k
self.soma().leak.erev = self.e_leak
self.species_scaling(
silent=True, species=species, modelType=modelType
) # set the default type II cell parameters
else: # decorate according to a defined set of rules on all cell compartments
self.decorate()
self.save_all_mechs() # save all mechanisms inserted, location and gbar values...
self.get_mechs(self.soma)
if debug:
print("<< SGC: Spiral Ganglion Cell created >>")
def get_cellpars(self, dataset, species="guineapig", celltype="sgc-a"):
cellcap = data.get(
dataset, species=species, cell_type=celltype, field="soma_Cap"
)
chtype = data.get(
dataset, species=species, cell_type=celltype, field="soma_na_type"
)
pars = Params(soma_Cap=cellcap, natype=chtype)
for g in [
"soma_na_gbar",
"soma_kht_gbar",
"soma_klt_gbar",
"soma_ihap_gbar",
"soma_ihbm_gbar",
"soma_ihap_eh",
"soma_ihbm_eh",
"soma_leak_gbar",
"soma_leak_erev",
"soma_e_k",
"soma_e_na",
]:
pars.additem(
g, data.get(dataset, species=species, cell_type=celltype, field=g)
)
return pars
def species_scaling(self, silent=True, species="guineapig", modelType="a"):
"""
Adjust all of the conductances and the cell size according to the species requested.
Used ONLY for point models.
Parameters
----------
species : string (default: 'guineapig')
name of the species to use for scaling the conductances in the base point model
Must be one of mouse or guineapig
modelType: string (default: 'a')
definition of HCN model type from Liu et al. JARO 2014:
'a' for apical model
'bm' for basal-middle model
silent : boolean (default: True)
run silently (True) or verbosely (False)
Returns
-------
Nothing
Notes
-----
The 'guineapig' model uses the mouse HCN channel model, verbatim. This may not
be appropriate, given that the other conductances are scaled up.
"""
soma = self.soma
if modelType == "a":
celltype = "sgc-a"
elif modelType == "bm":
celltype = "sgc-bm"
else:
raise ValueError("SGC: unrecognized model type %s " % modelType)
if species == "mouse":
self._valid_temperatures = (34.0,)
if self.status["temperature"] is None:
self.set_temperature(34.0)
par = self.get_cellpars(
"sgc_mouse_channels", species=species, celltype=celltype
)
elif species == "guineapig":
# guinea pig data from Rothman and Manis, 2003, modelType II
self._valid_temperatures = (22.0,)
if self.status["temperature"] is None:
self.set_temperature(22.0)
par = self.get_cellpars(
"sgc_guineapig_channels", species=species, celltype=celltype
)
self.set_soma_size_from_Cm(par.soma_Cap)
self.adjust_na_chans(soma, gbar=par.soma_na_gbar)
soma().kht.gbar = nstomho(par.soma_kht_gbar, self.somaarea)
soma().klt.gbar = nstomho(par.soma_klt_gbar, self.somaarea)
if celltype == "sgc-a":
soma().ihsgcApical.gbar = nstomho(par.soma_ihap_gbar, self.somaarea)
soma().ihsgcApical.eh = par.soma_ihap_eh
elif celltype == "sgc-bm":
soma().ihsgcBasalMiddle.gbar = nstomho(par.soma_ihbm_gbar, self.somaarea)
soma().ihsgcBasalMiddle.eh = par.soma_ihbm_eh
else:
raise ValueError(
"Ihsgc modelType %s not recognized for species %s" % (celltype, species)
)
soma().leak.gbar = nstomho(par.soma_leak_gbar, self.somaarea)
soma().leak.erev = par.soma_leak_erev
self.status["species"] = species
self.status["modelType"] = modelType
self.check_temperature()
if not silent:
print("set cell as: ", species)
print(" with Vm rest = %f" % self.vm0)
def adjust_na_chans(self, soma, gbar=1000.0, debug=False):
"""
adjust the sodium channel conductance
:param soma: a soma object whose sodium channel complement will have it's
conductances adjusted depending on the channel type
:return nothing:
"""
if self.status["ttx"]:
gnabar = 0.0
else:
gnabar = nstomho(gbar, self.somaarea)
nach = self.status["na"]
if nach == "jsrna":
soma().jsrna.gbar = gnabar
soma.ena = self.e_na
if debug:
print("jsrna gbar: ", soma().jsrna.gbar)
elif nach == "nav11":
soma().nav11.gbar = gnabar * 0.5
soma.ena = self.e_na
soma().nav11.vsna = 4.3
if debug:
print("sgc using inva11")
print("nav11 gbar: ", soma().nav11.gbar)
elif nach in ["na", "nacn"]:
soma().na.gbar = gnabar
soma.ena = self.e_na
if debug:
print("na gbar: ", soma().na.gbar)
else:
raise ValueError("Sodium channel %s is not recognized for SGC cells", nach)
def i_currents(self, V):
"""
For the steady-state case, return the total current at voltage V
Used to find the zero current point
vrange brackets the interval
Implemented here are the basic RM03 mechanisms
This function should be replaced for specific cell types.
"""
for part in self.all_sections.keys():
for sec in self.all_sections[part]:
sec.v = V
h.t = 0.0
h.celsius = self.status["temperature"]
h.finitialize()
self.ix = {}
if "na" in self.mechanisms:
# print dir(self.soma().na)
self.ix["na"] = self.soma().na.gna * (V - self.soma().ena)
if "jsrna" in self.mechanisms:
# print dir(self.soma().na)
self.ix["jsrna"] = self.soma().jsrna.gna * (V - self.soma().ena)
if "klt" in self.mechanisms:
self.ix["klt"] = self.soma().klt.gklt * (V - self.soma().ek)
if "kht" in self.mechanisms:
self.ix["kht"] = self.soma().kht.gkht * (V - self.soma().ek)
if "ihsgcApical" in self.mechanisms:
self.ix["ihsgcApical"] = self.soma().ihsgcApical.gh * (
V - self.soma().ihsgcApical.eh
)
if "ihsgcBasalMiddle" in self.mechanisms:
self.ix["ihsgcBasalMiddle"] = self.soma().ihsgcBasalMiddle.gh * (
V - self.soma().ihsgcBasalMiddle.eh
)
if "leak" in self.mechanisms:
self.ix["leak"] = self.soma().leak.gbar * (V - self.soma().leak.erev)
# print self.status['name'], self.status['type'], V, self.ix
return np.sum([self.ix[i] for i in self.ix])