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.
467 lines
17 KiB
467 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])
|
|
|