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

23
cnmodel/cells/__init__.py Normal file
View File

@@ -0,0 +1,23 @@
"""
Cell definitions for models.
This class includes a number of different cell definitions and default
conductances for point models.
"""
from .bushy import *
from .tstellate import *
from .dstellate import *
from .cartwheel import *
from .pyramidal import *
from .sgc import *
from .octopus import *
from .tuberculoventral import *
from .msoprincipal import *
from .hh import *
from .cell import Cell
def cell_from_section(sec):
return Cell.from_section(sec)

967
cnmodel/cells/bushy.py Normal file
View File

@@ -0,0 +1,967 @@
from __future__ import print_function
from neuron import h
from collections import OrderedDict
from .cell import Cell
from .. import synapses
from ..util import nstomho
from ..util import Params
import numpy as np
from .. import data
import pprint
pp = pprint.PrettyPrinter(indent=4, width=60)
__all__ = ["Bushy", "BushyRothman"]
class Bushy(Cell):
type = "bushy"
@classmethod
def create(cls, model="RM03", **kwds):
if model == "RM03":
return BushyRothman(**kwds)
else:
raise ValueError("Bushy model %s is unknown", model)
def make_psd(self, terminal, psd_type, **kwds):
"""
Connect a presynaptic terminal to one post section at the specified location, with the fraction
of the "standard" conductance determined by gbar.
The default condition is designed to pass the unit test (loc=0.5)
Parameters
----------
terminal : Presynaptic terminal (NEURON object)
psd_type : either simple or multisite PSD for bushy cell
kwds: dictionary of options.
Two are currently handled:
postsite : expect a list consisting of [sectionno, location (float)]
AMPAScale : float to scale the ampa currents
"""
if (
"postsite" in kwds
): # use a defined location instead of the default (soma(0.5)
postsite = kwds["postsite"]
loc = postsite[1] # where on the section?
uname = (
"sections[%d]" % postsite[0]
) # make a name to look up the neuron section object
post_sec = self.hr.get_section(uname) # Tell us where to put the synapse.
else:
loc = 0.5
post_sec = self.soma
if psd_type == "simple":
if terminal.cell.type in ["sgc", "dstellate", "tuberculoventral"]:
weight = data.get(
"%s_synapse" % terminal.cell.type,
species=self.species,
post_type=self.type,
field="weight",
)
tau1 = data.get(
"%s_synapse" % terminal.cell.type,
species=self.species,
post_type=self.type,
field="tau1",
)
tau2 = data.get(
"%s_synapse" % terminal.cell.type,
species=self.species,
post_type=self.type,
field="tau2",
)
erev = data.get(
"%s_synapse" % terminal.cell.type,
species=self.species,
post_type=self.type,
field="erev",
)
return self.make_exp2_psd(
post_sec,
terminal,
weight=weight,
loc=loc,
tau1=tau1,
tau2=tau2,
erev=erev,
)
else:
raise TypeError(
"Cannot make simple PSD for %s => %s"
% (terminal.cell.type, self.type)
)
elif psd_type == "multisite":
if terminal.cell.type == "sgc":
# Max conductances for the glu mechanisms are calibrated by
# running `synapses/tests/test_psd.py`. The test should fail
# if these values are incorrect
self.AMPAR_gmax = (
data.get(
"sgc_synapse",
species=self.species,
post_type=self.type,
field="AMPAR_gmax",
)
* 1e3
)
self.NMDAR_gmax = (
data.get(
"sgc_synapse",
species=self.species,
post_type=self.type,
field="NMDAR_gmax",
)
* 1e3
)
self.Pr = data.get(
"sgc_synapse", species=self.species, post_type=self.type, field="Pr"
)
self.NMDAR_vshift = data.get(
"sgc_synapse",
species=self.species,
post_type=self.type,
field="NMDAR_vshift",
)
# adjust gmax to correct for initial Pr
self.AMPAR_gmax = self.AMPAR_gmax / self.Pr
self.NMDAR_gmax = self.NMDAR_gmax / self.Pr
# original values (now in synapses.py):
# self.AMPA_gmax = 3.314707700918133*1e3 # factor of 1e3 scales to pS (.mod mechanisms) from nS.
# self.NMDA_gmax = 0.4531929783503451*1e3
if "AMPAScale" in kwds: # normally, this should not be done!
self.AMPAR_gmax = (
self.AMPAR_gmax * kwds["AMPAScale"]
) # allow scaling of AMPA conductances
if "NMDAScale" in kwds:
self.NMDAR_gmax = self.NMDAR_gmax * kwds["NMDAScale"] # and NMDA...
return self.make_glu_psd(
post_sec,
terminal,
self.AMPAR_gmax,
self.NMDAR_gmax,
loc=loc,
nmda_vshift=self.NMDAR_vshift,
)
elif terminal.cell.type == "dstellate":
return self.make_gly_psd(post_sec, terminal, psdtype="glyslow", loc=loc)
elif terminal.cell.type == "tuberculoventral":
return self.make_gly_psd(post_sec, terminal, psdtype="glyslow", loc=loc)
else:
raise TypeError(
"Cannot make PSD for %s => %s" % (terminal.cell.type, self.type)
)
else:
raise ValueError("Unsupported psd type %s" % psd_type)
def make_terminal(self, post_cell, term_type, **kwds):
if term_type == "simple":
return synapses.SimpleTerminal(self.soma, post_cell, **kwds)
elif term_type == "multisite":
if post_cell.type in ["mso"]:
nzones = data.get(
"bushy_synapse",
species=self.species,
post_type=post_cell.type,
field="n_rsites",
)
delay = data.get(
"bushy_synapse",
species=self.species,
post_type=post_cell.type,
field="delay",
)
else:
raise NotImplementedError(
"No knowledge as to how to connect Bushy cell to cell type %s"
% type(post_cell)
)
pre_sec = self.soma
return synapses.StochasticTerminal(
pre_sec,
post_cell,
nzones=nzones,
spike_source=self.spike_source,
delay=delay,
**kwds,
)
else:
raise ValueError("Unsupported terminal type %s" % term_type)
class BushyRothman(Bushy):
"""
VCN bushy cell models.
Rothman and Manis, 2003abc (Type II, Type II-I)
Xie and Manis, 2013
"""
def __init__(
self,
morphology=None,
decorator=None,
nach=None,
ttx=False,
species="guineapig",
modelType=None,
modelName=None,
debug=False,
temperature=None,
):
"""
Create a bushy cell, using the default parameters for guinea pig from
R&M2003, as a type II cell.
Additional modifications to the cell can be made by calling methods below.
Parameters
----------
morphology : string (default: None)
Name of a .hoc file representing the morphology. This file is used to constructe
an electrotonic (cable) model.
If None (default), then a "point" (really, single cylinder) 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 is inserted into the first soma section, and the
rest of the structure is "bare".
nach : string (default: None)
nach selects the type of sodium channel that will be used in the model. A channel mechanism
by that name must exist. The default channel is set to 'nacn' (R&M03)
temperature : float (default: 22)
temperature to run the cell at.
ttx : Boolean (default: False)
If ttx is True, then the sodium channel conductance is set to 0 everywhere in the cell.
This flag duplicates the effects of tetrodotoxin in the model. Currently, the flag is not implemented.
species: string (default 'guineapig')
species defines the pattern of ion channel densities that will be inserted, according to
prior measurements in various species. Note that
if a decorator function is specified, this argument is ignored as the decorator will
specify the channel density.
modelName: string (default: None)
modelName specifies the source conductance pattern (RM03, XM13, etc).
modelName is passed to the decorator, or to species_scaling to adjust point (single cylinder) models.
modelType: string (default: None)
modelType specifies the subtype of the cell model that will be used (e.g., "II", "II-I", etc).
modelType is passed to the decorator, or to species_scaling to adjust point (single cylinder) models.
debug: boolean (default: False)
When True, there will be multiple printouts of progress and parameters.
Returns
-------
Nothing
"""
super(BushyRothman, self).__init__()
self.i_test_range = {
"pulse": (-1, 1, 0.05)
} # note that this might get reset with decorator according to channels
# Changing the default values will cause the unit tests to fail!
if modelType == None:
modelType = "II"
if species == "guineapig":
modelName = "RM03"
temp = 22.0
if nach == None:
nach = "na"
if species == "mouse":
temp = 34.0
if modelName is None:
modelName = "XM13"
if nach is None:
nach = "na"
self.debug = debug
self.status = {
"species": species,
"cellClass": self.type,
"modelType": modelType,
"modelName": modelName,
"soma": True,
"axon": False,
"dendrites": False,
"pumps": False,
"hillock": False,
"initialsegment": False,
"myelinatedaxon": False,
"unmyelinatedaxon": False,
"na": nach,
"ttx": ttx,
"name": self.type,
"morphology": morphology,
"decorator": decorator,
"temperature": temperature,
}
self.spike_threshold = -40
self.vrange = [-70.0, -55.0] # set a default vrange for searching for rmp
if self.debug:
print(
"model type, model name, species: ", modelType, modelName, species, nach
)
self.c_m = 0.9e-6 # default in units of F/cm^2
self._valid_temperatures = (temp,)
if self.status["temperature"] == None:
self.status["temperature"] = temp
if morphology is None:
"""
instantiate a basic soma-only ("point") model
"""
if self.debug:
print("<< Bushy model: Creating point cell >>")
soma = h.Section(
name="Bushy_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
"""
if self.debug:
print(
"<< Bushy model: Creating cell with morphology from %s >>"
% morphology
)
self.set_morphology(morphology_file=morphology)
# decorate the morphology with ion channels
if decorator is None: # basic model, only on the soma, does not use tables.
self.mechanisms = ["klt", "kht", "ihvcn", "leak", nach]
for mech in self.mechanisms:
self.soma.insert(mech)
self.soma.ena = self.e_na
self.soma.ek = self.e_k
self.soma().ihvcn.eh = self.e_h
self.soma().leak.erev = self.e_leak
self.c_m = 0.9
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, with tables.
self.decorate()
self.save_all_mechs() # save all mechanisms inserted, location and gbar values...
self.get_mechs(self.soma)
if debug:
print(" << Created cell >>")
def get_cellpars(self, dataset, species="guineapig", modelType="II"):
"""
Read data for ion channels and cell parameters from the tables
"""
# cell_type = self.map_celltype(cell_type)
# print('getcellpars: dataset, species, mmodeltype: ', dataset, species, modelType)
# print('model name: ', self.status['modelName'])
cellcap = data.get(
dataset, species=species, model_type=modelType, field="soma_Cap"
)
chtype = data.get(
dataset, species=species, model_type=modelType, field="na_type"
)
pars = Params(cap=cellcap, natype=chtype)
# print('pars cell/chtype: ')
if self.debug:
pars.show()
if self.status["modelName"] == "RM03":
for g in [
"%s_gbar" % pars.natype,
"kht_gbar",
"klt_gbar",
"ih_gbar",
"leak_gbar",
]:
pars.additem(
g, data.get(dataset, species=species, model_type=modelType, field=g)
)
if self.status["modelName"] == "XM13":
for g in [
"%s_gbar" % pars.natype,
"kht_gbar",
"klt_gbar",
"ihvcn_gbar",
"leak_gbar",
]:
pars.additem(
g, data.get(dataset, species=species, model_type=modelType, field=g)
)
if self.status["modelName"] == "mGBC":
for g in [
"%s_gbar" % pars.natype,
"kht_gbar",
"klt_gbar",
"ihvcn_gbar",
"leak_gbar",
]:
pars.additem(
g, data.get(dataset, species=species, model_type=modelType, field=g)
)
return pars
def species_scaling(self, species="guineapig", modelType="II", silent=True):
"""
This is called for POINT CELLS ONLY
Adjust all of the conductances and the cell size according to the species requested.
This scaling should be used ONLY for point models, as no other compartments
are scaled.
This scaling routine also sets the temperature for the model to a default value. Some models
can be run at multiple temperatures, and so a default from one of the temperatures is used.
The calling cell.set_temperature(newtemp) will change the conductances and reinitialize
the cell to the new temperature settings.
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, cat, guineapig
modelType: string (default: 'II')
definition of model type from RM03 models, type II or type II-I
silent : boolean (default: True)
run silently (True) or verbosely (False)
"""
# print '\nSpecies scaling: %s %s' % (species, type)
knownspecies = ["mouse", "guineapig", "cat"]
soma = self.soma
# cellType = self.map_celltype(modelType)
if species == "mouse":
# use conductance levels determined from Cao et al., J. Neurophys., 2007. as
# model description in Xie and Manis 2013. Note that
# conductances were not scaled for temperature (rates were)
# so here we reset the default Q10's for conductance (g) to 1.0
if modelType not in ["II", "II-I"]:
raise ValueError(
"\nModel type %s is not implemented for mouse bushy cells"
% modelType
)
if self.debug:
print(
" Setting conductances for mouse bushy cell (%s), Xie and Manis, 2013"
% modelType
)
if modelname == "XM13":
dataset = "XM13_channels"
elif modelname == "XM13nacncoop":
dataset = "XM13_channels_nacncoop"
elif modelname.startswith("mGBC"):
dataset = "mGBC_channels"
else:
raise ValueError(
f"ModelName {modelname:s} not recognized for mouse bushy cells"
)
self.vrange = [-68.0, -55.0] # set a default vrange for searching for rmp
self.i_test_range = {"pulse": (-1.0, 1.0, 0.05)}
self._valid_temperatures = (34.0,)
if self.status["temperature"] is None:
self.status["temperature"] = 34.0
pars = self.get_cellpars(dataset, species=species, modelType=modelType)
self.set_soma_size_from_Cm(pars.cap)
self.status["na"] = pars.natype
self.adjust_na_chans(soma, sf=1.0)
soma().kht.gbar = nstomho(pars.kht_gbar, self.somaarea)
soma().klt.gbar = nstomho(pars.klt_gbar, self.somaarea)
soma().ihvcn.gbar = nstomho(pars.ihvcn_gbar, self.somaarea)
soma().leak.gbar = nstomho(pars.leak_gbar, self.somaarea)
self.axonsf = 0.57
elif species == "guineapig":
if self.debug:
print(
" Setting conductances for guinea pig %s bushy cell, Rothman and Manis, 2003"
% modelType
)
self._valid_temperatures = (22.0, 38.0)
if self.status["temperature"] is None:
self.status["temperature"] = 22.0
self.i_test_range = {"pulse": (-0.4, 0.4, 0.02)}
sf = 1.0
if (
self.status["temperature"] == 38.0
): # adjust for 2003 model conductance levels at 38
sf = 2 # Q10 of 2, 22->38C. (p3106, R&M2003c)
# note that kinetics are scaled in the mod file.
dataset = "RM03_channels"
pars = self.get_cellpars(dataset, species=species, modelType=modelType)
self.set_soma_size_from_Cm(pars.cap)
self.status["na"] = pars.natype
self.adjust_na_chans(soma, sf=sf)
soma().kht.gbar = nstomho(pars.kht_gbar, self.somaarea)
soma().klt.gbar = nstomho(pars.klt_gbar, self.somaarea)
soma().ihvcn.gbar = nstomho(pars.ih_gbar, self.somaarea)
soma().leak.gbar = nstomho(pars.leak_gbar, self.somaarea)
self.axonsf = 0.57
else:
errmsg = (
'Species "%s" or model type "%s" is not recognized for Bushy cells.'
% (species, modelType)
)
errmsg += "\n Valid species are: \n"
for s in knownspecies:
errmsg += " %s\n" % s
errmsg += "-" * 40
raise ValueError(errmsg)
self.status["species"] = species
self.status["modelType"] = modelType
self.check_temperature()
# self.cell_initialize(vrange=self.vrange) # no need to do this just yet.
if not silent:
print(" set cell as: ", species)
print(" with Vm rest = %6.3f" % self.vm0)
# def channel_manager(self, modelType='RM03', cell_type='bushy-II'):
# """
# This routine defines channel density maps and distance map patterns
# for each type of compartment in the cell. The maps
# are used by the ChannelDecorator class (specifically, its private
# \_biophys function) to decorate the cell membrane.
# These settings are only used if the decorator is called; otherwise
# for point cells, the species_scaling routine defines the channel
# densities.
#
# Parameters
# ----------
# modelType : string (default: 'RM03')
# A string that defines the type of the model. Currently, 3 types are implemented:
# RM03: Rothman and Manis, 2003 somatic densities for guinea pig
# XM13: Xie and Manis, 2013, somatic densities for mouse
# mGBC: experimental mouse globular bushy cell with dendrites, axon, hillock and initial segment, for
# use with fully reconstructed neurons.
#
# Returns
# -------
# Nothing
#
# Notes
# -----
# This routine defines the following variables for the class:
#
# * conductances (gBar)
# * a channelMap (dictonary of channel densities in defined anatomical compartments)
# * a current injection range for IV's (used for testing)
# * a distance map, which defines how each conductance in a selected compartment
# changes with distance from the soma. The current implementation includes both
# linear and exponential gradients,
# the minimum conductance at the end of the gradient, and the space constant or
# slope for the gradient.
#
# """
#
#
# dataset = '%s_channels' % modelType
# decorationmap = dataset + '_compartments'
# # print('dataset: {0:s} decorationmap: {1:s}'.format(dataset, decorationmap))
# cellpars = self.get_cellpars(dataset, species=self.status['species'], celltype=cell_type)
# refarea = 1e-3*cellpars.cap / self.c_m
#
# table = data.get_table_info(dataset)
# chscale = data.get_table_info(decorationmap)
# pars = {}
# # retrive the conductances from the data set
# for g in table['field']:
# x = data.get(dataset, species=self.status['species'], cell_type=cell_type,
# field=g)
# if not isinstance(x, float):
# continue
# if '_gbar' in g:
# pars[g] = x/refarea
# else:
# pars[g] = x
#
# self.channelMap = OrderedDict()
# for c in chscale['compartment']:
# self.channelMap[c] = {}
# for g in pars.keys():
# if g not in chscale['parameter']:
# # print ('Parameter %s not found in chscale parameters!' % g)
# continue
# scale = data.get(decorationmap, species=self.status['species'], cell_type=cell_type,
# compartment=c, parameter=g)
# if '_gbar' in g:
# self.channelMap[c][g] = pars[g]*scale
# else:
# self.channelMap[c][g] = pars[g]
#
# self.irange = np.linspace(-0.6, 1, 9)
def get_distancemap(self):
return {
"dend": {
"klt": {"gradient": "exp", "gminf": 0.0, "lambda": 50.0},
"kht": {"gradient": "exp", "gminf": 0.0, "lambda": 50.0},
"nav11": {"gradient": "exp", "gminf": 0.0, "lambda": 50.0},
}, # linear with distance, gminf (factor) is multiplied by gbar
"dendrite": {
"klt": {"gradient": "linear", "gminf": 0.0, "lambda": 100.0},
"kht": {"gradient": "linear", "gminf": 0.0, "lambda": 100.0},
"nav11": {"gradient": "linear", "gminf": 0.0, "lambda": 100.0},
}, # linear with distance, gminf (factor) is multiplied by gbar
"apic": {
"klt": {"gradient": "linear", "gminf": 0.0, "lambda": 100.0},
"kht": {"gradient": "linear", "gminf": 0.0, "lambda": 100.0},
"nav11": {"gradient": "exp", "gminf": 0.0, "lambda": 200.0},
}, # gradients are: flat, linear, exponential
}
# self.check_temperature()
# return
#
#
#
# if modelType == 'RM03':
# #
# # Create a model based on the Rothman and Manis 2003 conductance set from guinea pig
# #
# self.c_m = 0.9E-6 # default in units of F/cm^2
# self._valid_temperatures = (22., 38.)
# sf = 1.0
# if self.status['temperature'] == None:
# self.status['temperature'] = 22.
# if self.status['temperature'] == 38:
# sf = 3.03
# dataset = 'RM03_channels'
# pars = self.get_cellpars(dataset, species=self.status['species'], celltype='bushy-II')
# refarea = 1e-3*pars.cap / self.c_m
# self.gBar = Params(nabar=sf*pars.soma_na_gbar/refarea, # 1000.0E-9/refarea,
# khtbar=sf*pars.soma_kht_gbar/refarea,
# kltbar=sf*pars.soma_klt_gbar/refarea,
# ihbar=sf*pars.soma_ih_gbar/refarea,
# leakbar=sf*pars.soma_leak_gbar/refarea,
# )
# print 'RM03 gbar:\n', self.gBar.show()
#
# self.channelMap = {
# 'axon': {'nacn': self.gBar.nabar, 'klt': self.gBar.kltbar, 'kht': self.gBar.khtbar, 'ihvcn': 0.,
# 'leak': self.gBar.leakbar / 2.},
# 'hillock': {'nacn': self.gBar.nabar, 'klt': self.gBar.kltbar, 'kht': self.gBar.khtbar, 'ihvcn': 0.,
# 'leak': self.gBar.leakbar, },
# 'initseg': {'nacn': self.gBar.nabar, 'klt': self.gBar.kltbar, 'kht': self.gBar.khtbar,
# 'ihvcn': self.gBar.ihbar / 2., 'leak': self.gBar.leakbar, },
# 'soma': {'nacn': self.gBar.nabar, 'klt': self.gBar.kltbar, 'kht': self.gBar.khtbar,
# 'ihvcn': self.gBar.ihbar, 'leak': self.gBar.leakbar, },
# 'dend': {'nacn': self.gBar.nabar, 'klt': self.gBar.kltbar * 0.5, 'kht': self.gBar.khtbar * 0.5,
# 'ihvcn': self.gBar.ihbar / 3., 'leak': self.gBar.leakbar * 0.5, },
# 'apic': {'nacn': self.gBar.nabar, 'klt': self.gBar.kltbar * 0.2, 'kht': self.gBar.khtbar * 0.2,
# 'ihvcn': self.gBar.ihbar / 4., 'leak': self.gBar.leakbar * 0.2, },
# }
# # self.irange = np.linspace(-1., 1., 21)
# self.distMap = {'dend': {'klt': {'gradient': 'linear', 'gminf': 0., 'lambda': 100.},
# 'kht': {'gradient': 'linear', 'gminf': 0., 'lambda': 100.},
# 'nacn': {'gradient': 'exp', 'gminf': 0., 'lambda': 100.}}, # linear with distance, gminf (factor) is multiplied by gbar
# 'apic': {'klt': {'gradient': 'linear', 'gminf': 0., 'lambda': 100.},
# 'kht': {'gradient': 'linear', 'gminf': 0., 'lambda': 100.},
# 'nacn': {'gradient': 'exp', 'gminf': 0., 'lambda': 100.}}, # gradients are: flat, linear, exponential
# }
#
# elif modelType == 'XM13':
# #
# # Create a model for a mouse bushy cell from Xie and Manis, 2013
# # based on Cao and Oertel mouse conductance values
# # and Rothman and Manis kinetics.
# self.c_m = 0.9E-6 # default in units of F/cm^2
# self._valid_temperatures = (34., )
# if self.status['temperature'] == None:
# self.status['temperature'] = 34.
# dataset = 'XM13_channels'
# pars = self.get_cellpars(dataset, species=self.status['species'], celltype='bushy-II')
# refarea = 1e-3*pars.cap / self.c_m
# # self.gBar = Params(nabar=pars.soma_nav11_gbar/refarea, # 1000.0E-9/refarea,
# # khtbar=pars.soma_kht_gbar/refarea,
# # kltbar=pars.soma_klt_gbar/refarea,
# # ihbar=pars.soma_ihvcn_gbar/refarea,
# # leakbar=pars.soma_leak_gbar/refarea,
# # )
# # print 'XM13 gbar:\n', self.gBar.show()
# # # create channel map:
# decorationmap = 'XM13_channels_bycompartment'
#
# table = data.get_table_info(dataset)
# pars = {}
# for g in table['field']:
# x = data.get(dataset, species=self.status['species'], cell_type='bushy-II',
# field=g)
# if not isinstance(x, float):
# continue
# pars[g] = (1./refarea)*data.get(dataset, species=self.status['species'], cell_type='bushy-II',
# field=g)
# chscale = data.get_table_info(decorationmap)
# self.channelMap1 = OrderedDict()
# # print chscale['parameter']
# for c in chscale['compartment']:
# self.channelMap1[c] = {}
# for g in pars.keys():
# # print g
# if g[5:] not in chscale['parameter']:
# continue
# scale = data.get(decorationmap, species=self.status['species'], cell_type='bushy-II',
# compartment=c, parameter=g[5:])
# self.channelMap1[c][g] = pars[g]*scale
#
# #
# # self.channelMap = {
# # 'unmyelinatedaxon': {'nav11': self.gBar.nabar*1, 'klt': self.gBar.kltbar * 1.0, 'kht': self.gBar.khtbar, 'ihvcn': 0.,
# # 'leak': self.gBar.leakbar * 0.25},
# # 'hillock': {'nav11': self.gBar.nabar*2, 'klt': self.gBar.kltbar, 'kht': self.gBar.khtbar*2.0, 'ihvcn': 0.,
# # 'leak': self.gBar.leakbar, },
# # 'initialsegment': {'nav11': self.gBar.nabar*3.0, 'klt': self.gBar.kltbar*1, 'kht': self.gBar.khtbar*2,
# # 'ihvcn': self.gBar.ihbar * 0.5, 'leak': self.gBar.leakbar, },
# # 'soma': {'nav11': self.gBar.nabar*1.0, 'klt': self.gBar.kltbar, 'kht': self.gBar.khtbar,
# # 'ihvcn': self.gBar.ihbar, 'leak': self.gBar.leakbar, },
# # 'dend': {'nav11': self.gBar.nabar * 0.25, 'klt': self.gBar.kltbar *0.5, 'kht': self.gBar.khtbar *0.5,
# # 'ihvcn': self.gBar.ihbar *0.5, 'leak': self.gBar.leakbar * 0.5, },
# # 'primarydendrite': {'nav11': self.gBar.nabar * 0.25, 'klt': self.gBar.kltbar *0.5, 'kht': self.gBar.khtbar *0.5,
# # 'ihvcn': self.gBar.ihbar *0.5, 'leak': self.gBar.leakbar * 0.5, },
# # 'apic': {'nav11': self.gBar.nabar * 0.25, 'klt': self.gBar.kltbar * 0.25, 'kht': self.gBar.khtbar * 0.25,
# # 'ihvcn': self.gBar.ihbar *0.25, 'leak': self.gBar.leakbar * 0.25, },
# # }
# import pprint
# # print 'original map:\n'
# # for k in self.channelMap.keys():
# # print('Region: %s' % k)
# # if k in self.channelMap1.keys():
# # print 'overlapping Region: %s' % k
# # for ch in self.channelMap[k].keys():
# # # print ch
# # # print self.channelMap1[k].keys()
# # # print self.channelMap[k].keys()
# # if 'soma_' + ch + '_gbar' in self.channelMap1[k].keys():
# # cx = u'soma_' + ch + u'_gbar'
# # # print ch, cx
# # print( ' {0:>4s} = {1:e} {2:e} {3:<5s}'.format(ch, self.channelMap[k][ch], self.channelMap1[k][cx],
# # str(np.isclose(self.channelMap[k][ch], self.channelMap1[k][cx]))))
#
# # print 'original: ', self.channelMap['soma']
# self.channelMap = self.channelMap1 # use the data table
# # except need to remove soma_ from keys
# for k in self.channelMap.keys():
# for n in self.channelMap[k].keys():
# new_key = n.replace('_gbar', '')
# # new_key = n
# new_key = new_key.replace('soma_', '')
# # strip 'soma_' from key
# #print 'newkey: ', new_key, n
# self.channelMap[k][new_key] = self.channelMap[k].pop(n)
#
# print 'final map: ', self.channelMap['soma']
#
# self.irange = np.linspace(-0.6, 1, 9)
# self.distMap = {'dend': {'klt': {'gradient': 'exp', 'gminf': 0., 'lambda': 50.},
# 'kht': {'gradient': 'exp', 'gminf': 0., 'lambda': 50.},
# 'nav11': {'gradient': 'exp', 'gminf': 0., 'lambda': 50.}}, # linear with distance, gminf (factor) is multiplied by gbar
# 'dendrite': {'klt': {'gradient': 'linear', 'gminf': 0., 'lambda': 100.},
# 'kht': {'gradient': 'linear', 'gminf': 0., 'lambda': 100.},
# 'nav11': {'gradient': 'linear', 'gminf': 0., 'lambda': 100.}}, # linear with distance, gminf (factor) is multiplied by gbar
# 'apic': {'klt': {'gradient': 'linear', 'gminf': 0., 'lambda': 100.},
# 'kht': {'gradient': 'linear', 'gminf': 0., 'lambda': 100.},
# 'nav11': {'gradient': 'exp', 'gminf': 0., 'lambda': 200.}}, # gradients are: flat, linear, exponential
# }
#
# elif modelType == 'mGBC':
# # bushy from Xie and Manis, 2013, based on Cao and Oertel mouse conductances,
# # BUT modified ad hoc for SBEM reconstructions.
# dataset = 'mGBC_channels'
#
# self._valid_temperatures = (34.,)
# if self.status['temperature'] == None:
# self.status['temperature'] = 34.
# pars = self.get_cellpars(dataset, species=self.status['species'], celltype='bushy-II')
# refarea = 1e-3*pars.cap / self.c_m
# print (pars.cap, pars.soma_kht_gbar, refarea) # refarea should be about 30e-6
#
# self.gBar = Params(nabar=pars.soma_na_gbar/refarea, # 1000.0E-9/refarea,
# khtbar=pars.soma_kht_gbar/refarea,
# kltbar=pars.soma_klt_gbar/refarea,
# ihbar=pars.soma_ih_gbar/refarea,
# leakbar=pars.soma_leak_gbar/refarea,
# )
# print 'mGBC gbar:\n', self.gBar.show()
# sodiumch = 'jsrna'
# self.channelMap = {
# 'axon': {sodiumch: self.gBar.nabar*1., 'klt': self.gBar.kltbar * 1.0, 'kht': self.gBar.khtbar, 'ihvcn': 0.,
# 'leak': self.gBar.leakbar * 0.25},
# 'unmyelinatedaxon': {sodiumch: self.gBar.nabar*3.0, 'klt': self.gBar.kltbar * 2.0,
# 'kht': self.gBar.khtbar*3.0, 'ihvcn': 0.,
# 'leak': self.gBar.leakbar * 0.25},
# 'myelinatedaxon': {sodiumch: self.gBar.nabar*0, 'klt': self.gBar.kltbar * 1e-2,
# 'kht': self.gBar.khtbar*1e-2, 'ihvcn': 0.,
# 'leak': self.gBar.leakbar * 0.25*1e-3},
# 'hillock': {sodiumch: self.gBar.nabar*4.0, 'klt': self.gBar.kltbar*1.0, 'kht': self.gBar.khtbar*3.0,
# 'ihvcn': 0., 'leak': self.gBar.leakbar, },
# 'initseg': {sodiumch: self.gBar.nabar*3.0, 'klt': self.gBar.kltbar*2, 'kht': self.gBar.khtbar*2,
# 'ihvcn': self.gBar.ihbar * 0.5, 'leak': self.gBar.leakbar, },
# 'soma': {sodiumch: self.gBar.nabar*0.65, 'klt': self.gBar.kltbar, 'kht': self.gBar.khtbar*1.5,
# 'ihvcn': self.gBar.ihbar, 'leak': self.gBar.leakbar, },
# 'dend': {sodiumch: self.gBar.nabar * 0.2, 'klt': self.gBar.kltbar *1, 'kht': self.gBar.khtbar *1,
# 'ihvcn': self.gBar.ihbar *0.5, 'leak': self.gBar.leakbar * 0.5, },
# 'dendrite': {sodiumch: self.gBar.nabar * 0.2, 'klt': self.gBar.kltbar *1, 'kht': self.gBar.khtbar *1,
# 'ihvcn': self.gBar.ihbar *0.5, 'leak': self.gBar.leakbar * 0.5, },
# 'apic': {sodiumch: self.gBar.nabar * 0.25, 'klt': self.gBar.kltbar * 0.25, 'kht': self.gBar.khtbar * 0.25,
# 'ihvcn': self.gBar.ihbar *0.25, 'leak': self.gBar.leakbar * 0.25, },
# }
# self.irange = np.arange(-1.5, 2.1, 0.25 )
# self.distMap = {'dend': {'klt': {'gradient': 'linear', 'gminf': 0., 'lambda': 100.},
# 'kht': {'gradient': 'linear', 'gminf': 0., 'lambda': 100.},
# sodiumch: {'gradient': 'linear', 'gminf': 0., 'lambda': 100.}}, # linear with distance, gminf (factor) is multiplied by gbar
# 'dendrite': {'klt': {'gradient': 'linear', 'gminf': 0., 'lambda': 20.},
# 'kht': {'gradient': 'linear', 'gminf': 0., 'lambda': 20.},
# sodiumch: {'gradient': 'linear', 'gminf': 0., 'lambda': 20.}}, # linear with distance, gminf (factor) is multiplied by gbar
# 'apic': {'klt': {'gradient': 'linear', 'gminf': 0., 'lambda': 100.},
# 'kht': {'gradient': 'linear', 'gminf': 0., 'lambda': 100.},
# sodiumch: {'gradient': 'exp', 'gminf': 0., 'lambda': 200.}}, # gradients are: flat, linear, exponential
# }
# else:
# raise ValueError('model type %s is not implemented' % modelType)
# self.check_temperature()
def adjust_na_chans(self, soma, sf=1.0, gbar=1000.0):
"""
adjust the sodium channel conductance
Parameters
----------
soma : neuron section object
A soma object whose sodium channel complement will have its
conductances adjusted depending on the channel type
gbar : float (default: 1000.)
The maximal conductance for the sodium channel
Returns
-------
Nothing :
"""
if self.status["ttx"]:
gnabar = 0.0
else:
gnabar = nstomho(gbar, self.somaarea) * sf
nach = self.status["na"]
if nach == "jsrna":
soma().jsrna.gbar = gnabar
soma.ena = self.e_na
if self.debug:
print("jsrna gbar: ", soma().jsrna.gbar)
elif nach == "nav11":
soma().nav11.gbar = gnabar
soma.ena = 50 # self.e_na
# print('gnabar: ', soma().nav11.gbar, ' vs: 0.0192307692308')
soma().nav11.vsna = 4.3
if self.debug:
print("bushy using inva11")
if nach == "nacncoop":
soma().nacncoop.gbar = gnabar
soma().nacncoop.KJ = 2000.0
soma().nacncoop.p = 0.25
somae().nacncoop.vsna = 0.0
soma.ena = self.e_na
if debug:
print("nacncoop gbar: ", soma().nacncoop.gbar)
elif nach in ["na", "nacn"]:
soma().na.gbar = gnabar
soma.ena = self.e_na
# soma().na.vsna = 0.
if self.debug:
print("na gbar: ", soma().na.gbar)
else:
raise ValueError(
"Sodium channel %s is not recognized for Bushy cells", nach
)
def add_axon(self):
"""
Add a default axon from the generic cell class to the bushy cell (see cell class).
"""
Cell.add_axon(self, self.c_m, self.R_a, self.axonsf)
def add_pumps(self):
"""
Insert mechanisms for potassium ion management, sodium ion management, and a
sodium-potassium pump at the soma.
"""
soma = self.soma
soma.insert("k_conc")
ki0_k_ion = 140
soma().ki = ki0_k_ion
soma().ki0_k_conc = ki0_k_ion
soma().beta_k_conc = 0.075
soma.insert("na_conc")
nai0_na_ion = 5
soma().nai = nai0_na_ion
soma().nai0_na_conc = nai0_na_ion
soma().beta_na_conc = 0.075
soma.insert("nakpump")
soma().nakpump.inakmax = 8
soma().nao = 145
soma().ko = 5
soma().nakpump.Nai_inf = 5
soma().nakpump.Ki_inf = 140
soma().nakpump.ATPi = 5
self.status["pumps"] = True
def add_dendrites(self):
"""
Add a simple dendrite to the bushy cell.
"""
if self.debug:
print("Adding dendrite to Bushy model")
section = h.Section
primarydendrite = section(cell=self.soma)
primarydendrite.connect(self.soma)
primarydendrite.nseg = 10
primarydendrite.L = 100.0
primarydendrite.diam = 2.5
primarydendrite.insert("klt")
primarydendrite.insert("ihvcn")
primarydendrite().klt.gbar = self.soma().klt.gbar / 2.0
primarydendrite().ihvcn.gbar = self.soma().ihvcn.gbar / 2.0
primarydendrite.cm = self.c_m
primarydendrite.Ra = self.R_a
nsecd = range(0, 5)
secondarydendrite = []
for ibd in nsecd:
secondarydendrite.append(section(cell=self.soma))
for ibd in nsecd:
secondarydendrite[ibd].connect(primarydendrite)
secondarydendrite[ibd].diam = 1.0
secondarydendrite[ibd].L = 15.0
secondarydendrite[ibd].cm = self.c_m
secondarydendrite[ibd].Ra = self.R_a
self.primarydendrite = primarydendrite
self.secondarydendrite = secondarydendrite
self.status["dendrite"] = True
if self.debug:
print("Bushy: added dendrites")
h.topology()
self.add_section(maindend, "primarydendrite")
self.add_section(secdend, "secondarydendrite")

447
cnmodel/cells/cartwheel.py Normal file
View File

@@ -0,0 +1,447 @@
from __future__ import print_function
import numpy as np
from neuron import h
from .cell import Cell
from .. import data
from .. import synapses
from ..util import Params
from ..util import nstomho
__all__ = ["Cartwheel", "CartwheelDefault"]
class Cartwheel(Cell):
type = "cartwheel"
@classmethod
def create(cls, model="CW", **kwds):
if model == "CW":
return CartwheelDefault(**kwds)
else:
raise ValueError("Carthweel model is unknown", model)
def make_psd(self, terminal, psd_type, **kwds):
"""
Connect a presynaptic terminal to one post section at the specified location, with the fraction
of the "standard" conductance determined by gbar.
The default condition is to try to pass the default unit test (loc=0.5)
Parameters
----------
terminal : Presynaptic terminal (NEURON object)
psd_type : either simple or multisite PSD for bushy cell
kwds: dict of options. Two are currently handled:
postsize : expect a list consisting of [sectionno, location (float)]
AMPAScale : float to scale the ampa currents
"""
self.pre_sec = terminal.section
pre_cell = terminal.cell
post_sec = self.soma
if psd_type == "simple":
if terminal.cell.type in [
"sgc",
"dstellate",
"tuberculoventral",
"cartwheel",
]:
weight = data.get(
"%s_synapse" % terminal.cell.type,
species=self.species,
post_type=self.type,
field="weight",
)
tau1 = data.get(
"%s_synapse" % terminal.cell.type,
species=self.species,
post_type=self.type,
field="tau1",
)
tau2 = data.get(
"%s_synapse" % terminal.cell.type,
species=self.species,
post_type=self.type,
field="tau2",
)
erev = data.get(
"%s_synapse" % terminal.cell.type,
species=self.species,
post_type=self.type,
field="erev",
)
return self.make_exp2_psd(
post_sec,
terminal,
weight=weight,
loc=loc,
tau1=tau1,
tau2=tau2,
erev=erev,
)
else:
raise TypeError(
"Cannot make simple PSD for %s => %s"
% (terminal.cell.type, self.type)
)
else:
raise ValueError(
"Unsupported psd type %s for cartwheel cell (inputs not implemented yet)"
% psd_type
)
def make_terminal(self, post_cell, term_type, **kwds):
if term_type == "simple":
return synapses.SimpleTerminal(self.soma, post_cell, **kwds)
elif term_type == "multisite":
if post_cell.type in ["tuberculoventral", "pyramidal"]:
nzones = data.get(
"cartwheel_synapse",
species=self.species,
post_type=post_cell.type,
field="n_rsites",
)
delay = data.get(
"cartwheel_synapse",
species=self.species,
post_type=post_cell.type,
field="delay",
)
else:
raise NotImplementedError(
"No knowledge as to how to connect cartwheel cell to cell type %s"
% type(post_cell)
)
pre_sec = self.soma
return synapses.StochasticTerminal(
pre_sec,
post_cell,
nzones=nzones,
spike_source=self.spike_source,
delay=delay,
**kwds
)
else:
raise ValueError("Unsupported terminal type %s" % term_type)
class CartwheelDefault(Cartwheel, Cell):
"""
DCN cartwheel cell model.
"""
def __init__(
self,
morphology=None,
decorator=None,
ttx=False,
nach=None,
species="mouse",
modelType=None,
debug=False,
):
"""
Create cartwheel cell model, based on a Purkinje cell model from Raman.
There are no variations available for this model.
Parameters
----------
morphology : string (default: None)
Name of a .hoc file representing the morphology. This file is used to constructe
an electrotonic (cable) model.
If None (default), then a "point" (really, single cylinder) 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 is inserted into the first soma section, and the
rest of the structure is "bare".
nach : string (default: None)
nach selects the type of sodium channel that will be used in the model. A channel mechanism
by that name must exist. The default is naRsg, a resurgent sodium channel model.
ttx : Boolean (default: False)
If ttx is True, then the sodium channel conductance is set to 0 everywhere in the cell.
This flag duplicates the effects of tetrodotoxin in the model. Currently, the flag is not implemented.
species: string (default 'rat')
species defines the pattern of ion channel densities that will be inserted, according to
prior measurements in various species. Note that
if a decorator function is specified, this argument is ignored as the decorator will
specify the channel density.
modelType: string (default: None)
modelType specifies the subtype of the cell model that will be used.
modelType is passed to the decorator, or to species_scaling to adjust point (single cylinder) models.
Only type "I" is recognized for the cartwheel cell model.
debug: boolean (default: False)
When True, there will be multiple printouts of progress and parameters.
Returns
-------
Nothing
"""
super(CartwheelDefault, self).__init__()
if modelType == None:
modelType = "I"
if nach == None:
nach = "naRsg"
self.status = {
"soma": True,
"axon": False,
"dendrites": False,
"pumps": False,
"na": nach,
"species": species,
"modelType": modelType,
"ttx": ttx,
"name": "Cartwheel",
"morphology": morphology,
"decorator": decorator,
"temperature": None,
}
self.i_test_range = {"pulse": (-0.2, 0.2, 0.02)}
# self.spike_threshold = 0
self.vrange = [-75.0, -52.0] # set a default vrange for searching for rmp
if morphology is None:
"""
instantiate a basic soma-only ("point") model
"""
soma = h.Section(
name="Cartwheel_Soma_%x" % id(self)
) # one compartment of about 29000 um2
# cm = 1
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
# v_potassium = -80 # potassium reversal potential
# v_sodium = 50 # sodium reversal potential
self.mechanisms = [
"naRsg",
"bkpkj",
"hpkj",
"kpkj",
"kpkj2",
"kpkjslow",
"kpksk",
"lkpkj",
"cap",
]
for mech in self.mechanisms:
self.soma.insert(mech)
self.soma.insert("cadiff")
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(
"<< Cartwheel: Modified version of Raman Purkinje cell model created >>"
)
def get_cellpars(self, dataset, species="guineapig", celltype="II"):
somaDia = data.get(
dataset, species=species, cell_type=celltype, field="soma_Dia"
)
chtype = data.get(
dataset, species=species, cell_type=celltype, field="soma_na_type"
)
pcabar = data.get(
dataset, species=species, cell_type=celltype, field="soma_pcabar"
)
pars = Params(soma_Dia=somaDia, soma_natype=chtype, soma_pcabar=pcabar)
for g in [
"soma_narsg_gbar",
"soma_kpkj_gbar",
"soma_kpkj2_gbar",
"soma_kpkjslow_gbar",
"soma_kpksk_gbar",
"soma_lkpkj_gbar",
"soma_bkpkj_gbar",
"soma_hpkj_gbar",
"soma_hpkj_eh",
"soma_lkpkj_e",
"soma_e_k",
"soma_e_na",
"soma_e_ca",
]:
pars.additem(
g, data.get(dataset, species=species, cell_type=celltype, field=g)
)
return pars
def species_scaling(self, silent=True, species="mouse", modelType="I"):
"""
Adjust all of the conductances and the cell size according to the species requested.
This scaling should be used ONLY for point models, as no other compartments
are scaled.
Parameters
----------
species : string (default: 'rat')
name of the species to use for scaling the conductances in the base point model
Must be one of mouse, cat, guineapig
modelType: string (default: 'I')
definition of model type from RM03 models, type II or type II-I
silent : boolean (default: True)
run silently (True) or verbosely (False)
Note
----
For the cartwheel cell model, there is only a single scaling recognized.
"""
if species is not "mouse":
raise ValueError('Cartwheel species: only "mouse" is recognized')
if modelType is not "I":
raise ValueError('Cartwheel modelType: only "I" is recognized')
self._valid_temperatures = (34.0,)
if self.status["temperature"] is None:
self.set_temperature(34.0)
pars = self.get_cellpars("CW_channels", species=species, celltype="cartwheel")
self.set_soma_size_from_Diam(pars.soma_Dia)
self.soma().bkpkj.gbar = nstomho(pars.soma_bkpkj_gbar, self.somaarea)
self.soma().hpkj.gbar = nstomho(pars.soma_hpkj_gbar, self.somaarea)
self.soma().kpkj.gbar = nstomho(pars.soma_kpkj_gbar, self.somaarea)
self.soma().kpkj2.gbar = nstomho(pars.soma_kpkj2_gbar, self.somaarea)
self.soma().kpkjslow.gbar = nstomho(pars.soma_kpkjslow_gbar, self.somaarea)
self.soma().kpksk.gbar = nstomho(pars.soma_kpksk_gbar, self.somaarea)
self.soma().lkpkj.gbar = nstomho(pars.soma_lkpkj_gbar, self.somaarea)
self.soma().naRsg.gbar = nstomho(pars.soma_narsg_gbar, self.somaarea)
self.soma().cap.pcabar = pars.soma_pcabar
self.soma().ena = pars.soma_e_na # 50
self.soma().ek = pars.soma_e_k # -80
self.soma().lkpkj.e = pars.soma_lkpkj_e # -65
self.soma().hpkj.eh = pars.soma_hpkj_eh # -43
self.soma().eca = pars.soma_e_ca # 50
self.status["na"] = pars.soma_natype
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)
# print 'set up'
def i_currents(self, V):
"""
For the steady-state case, return the total current at voltage V
Used to find the zero current point.
Overrides i_currents in cells.py, because this model uses conductances
that are not specified in the default cell mode.
Parameters
----------
V : float, mV (no default)
Voltage at which the current for each conductance is computed.
Returns
-------
I : float, nA
The sum of the currents at steady-state for all of the conductances.
"""
for part in self.all_sections.keys():
for sec in self.all_sections[part]:
sec.v = V
h.celsius = self.status["temperature"]
h.finitialize()
self.ix = {}
if "naRsg" in self.mechanisms:
self.ix["naRsg"] = self.soma().naRsg.gna * (V - self.soma().ena)
if "cap" in self.mechanisms:
a = self.soma().cap.pcabar * self.soma().cap.minf
self.ix["cap"] = a * self.ghk(V, self.soma().cao, self.soma().cai, 2)
if "kpkj" in self.mechanisms:
self.ix["kpkj"] = self.soma().kpkj.gk * (V - self.soma().ek)
if "kpkj2" in self.mechanisms:
self.ix["kpkj2"] = self.soma().kpkj2.gk * (V - self.soma().ek)
if "kpkjslow" in self.mechanisms:
self.ix["kpkjslow"] = self.soma().kpkjslow.gk * (V - self.soma().ek)
if "kpksk" in self.mechanisms:
self.ix["kpksk"] = self.soma().kpksk.gk * (V - self.soma().ek)
if "bkpkj" in self.mechanisms:
self.ix["bkpkj"] = self.soma().bkpkj.gbkpkj * (V - self.soma().ek)
if "hpkj" in self.mechanisms:
self.ix["hpkj"] = self.soma().hpkj.gh * (V - self.soma().hpkj.eh)
# leak
if "lkpkj" in self.mechanisms:
self.ix["lkpkj"] = self.soma().lkpkj.gbar * (V - self.soma().lkpkj.e)
return np.sum([self.ix[i] for i in self.ix])
def ghk(self, v, ci, co, z):
"""
GHK flux equation, used to calculate current density through calcium channels
rather than standard Nernst equation.
Parameters
----------
v : float, mV
voltage for GHK calculation
ci : float, mM
internal ion concentration
co : float, mM
external ion concentraion
z : float, no units
valence
Returns
-------
flux : A/m^2
"""
F = 9.6485e4 # (coul)
R = 8.3145 # (joule/degC)
T = h.celsius + 273.19 # Kelvin
E = (1e-3) * v # convert mV to V
Ci = ci + (self.soma().cap.monovalPerm) * (
self.soma().cap.monovalConc
) # : Monovalent permeability
if (
np.fabs(1 - np.exp(-z * (F * E) / (R * T))) < 1e-6
): # denominator is small -> Taylor series
ghk = (
(1e-6)
* z
* F
* (Ci - co * np.exp(-z * (F * E) / (R * T)))
* (1 - (z * (F * E) / (R * T)))
)
else:
ghk = (
(1e-6)
* z ** 2.0
* (E * F ** 2.0)
/ (R * T)
* (Ci - co * np.exp(-z * (F * E) / (R * T)))
/ (1 - np.exp(-z * (F * E) / (R * T)))
)
return ghk

1200
cnmodel/cells/cell.py Normal file

File diff suppressed because it is too large Load Diff

897
cnmodel/cells/dstellate.py Normal file
View File

@@ -0,0 +1,897 @@
from __future__ import print_function
from neuron import h
from ..util import nstomho
from .cell import Cell
from ..util import Params
from .. import synapses
from .. import data
__all__ = ["DStellate", "DStellateRothman", "DStellateEager"]
class DStellate(Cell):
type = "dstellate"
@classmethod
def create(cls, model="RM03", **kwds):
if model == "RM03":
return DStellateRothman(**kwds)
elif model == "Eager":
return DStellateEager(**kwds)
elif model == "dummy":
return DummyDStellate(**kwds)
else:
raise ValueError("DStellate type %s is unknown", type)
def __init__(self):
Cell.__init__(self)
self.spike_source = (
None
) # used by DummyDStellate to connect VecStim to terminal
def make_psd(self, terminal, psd_type, **kwds):
"""
Connect a presynaptic terminal to one post section at the specified location, with the fraction
of the "standard" conductance determined by gbar.
The default condition is designed to pass the unit test (loc=0.5)
Parameters
----------
terminal : Presynaptic terminal (NEURON object)
psd_type : either simple or multisite PSD for bushy cell
kwds: dictionary of options.
Two are currently handled:
postsize : expect a list consisting of [sectionno, location (float)]
AMPAScale : float to scale the ampa currents
"""
if (
"postsite" in kwds
): # use a defined location instead of the default (soma(0.5)
postsite = kwds["postsite"]
loc = postsite[1] # where on the section?
uname = (
"sections[%d]" % postsite[0]
) # make a name to look up the neuron section object
post_sec = self.hr.get_section(uname) # Tell us where to put the synapse.
else:
loc = 0.5
post_sec = self.soma
if psd_type == "simple":
if terminal.cell.type in ["sgc", "dstellate", "tuberculoventral"]:
weight = data.get(
"%s_synapse" % terminal.cell.type,
species=self.species,
post_type=self.type,
field="weight",
)
tau1 = data.get(
"%s_synapse" % terminal.cell.type,
species=self.species,
post_type=self.type,
field="tau1",
)
tau2 = data.get(
"%s_synapse" % terminal.cell.type,
species=self.species,
post_type=self.type,
field="tau2",
)
erev = data.get(
"%s_synapse" % terminal.cell.type,
species=self.species,
post_type=self.type,
field="erev",
)
return self.make_exp2_psd(
post_sec,
terminal,
weight=weight,
loc=loc,
tau1=tau1,
tau2=tau2,
erev=erev,
)
else:
raise TypeError(
"Cannot make simple PSD for %s => %s"
% (terminal.cell.type, self.type)
)
elif psd_type == "multisite":
if terminal.cell.type == "sgc":
# Max conductances for the glu mechanisms are calibrated by
# running `synapses/tests/test_psd.py`. The test should fail
# if these values are incorrect
self.AMPAR_gmax = (
data.get(
"sgc_synapse",
species=self.species,
post_type=self.type,
field="AMPAR_gmax",
)
* 1e3
)
self.NMDAR_gmax = (
data.get(
"sgc_synapse",
species=self.species,
post_type=self.type,
field="NMDAR_gmax",
)
* 1e3
)
self.Pr = data.get(
"sgc_synapse", species=self.species, post_type=self.type, field="Pr"
)
# adjust gmax to correct for initial Pr
self.AMPAR_gmax = self.AMPAR_gmax / self.Pr
self.NMDAR_gmax = self.NMDAR_gmax / self.Pr
# old values:
# AMPA_gmax = 0.22479596944138733*1e3 # factor of 1e3 scales to pS (.mod mechanisms) from nS.
# NMDA_gmax = 0.12281291946623739*1e3
if "AMPAScale" in kwds:
self.AMPAR_gmax = (
self.AMPAR_gmax * kwds["AMPAScale"]
) # allow scaling of AMPA conductances
if "NMDAScale" in kwds:
self.NMDAR_gmax = self.NMDAR_gmax * kwds["NMDAScale"]
return self.make_glu_psd(
post_sec, terminal, self.AMPAR_gmax, self.NMDAR_gmax, loc=loc
)
elif terminal.cell.type == "dstellate":
# Get GLY kinetic constants from database
return self.make_gly_psd(post_sec, terminal, psdtype="glyfast", loc=loc)
elif terminal.cell.type == "tuberculoventral":
# Get GLY kinetic constants from database
return self.make_gly_psd(post_sec, terminal, psdtype="glyfast", loc=loc)
else:
raise TypeError(
"Cannot make PSD for %s => %s" % (terminal.cell.type, self.type)
)
else:
raise ValueError("Unsupported psd type %s" % psd_type)
def make_terminal(self, post_cell, term_type, **kwds):
if term_type == "simple":
return synapses.SimpleTerminal(
self.soma, post_cell, spike_source=self.spike_source, **kwds
)
elif term_type == "multisite":
if post_cell.type in [
"dstellate",
"tuberculoventral",
"pyramidal",
"bushy",
"tstellate",
]:
nzones = data.get(
"dstellate_synapse",
species=self.species,
post_type=post_cell.type,
field="n_rsites",
)
delay = data.get(
"dstellate_synapse",
species=self.species,
post_type=post_cell.type,
field="delay",
)
else:
raise NotImplementedError(
"No knowledge as to how to connect D stellate cell to cell type %s"
% type(post_cell)
)
pre_sec = self.soma
return synapses.StochasticTerminal(
pre_sec,
post_cell,
nzones=nzones,
spike_source=self.spike_source,
delay=delay,
**kwds
)
else:
raise ValueError("Unsupported terminal type %s" % term_type)
class DStellateRothman(DStellate):
"""
VCN D-stellate model:
as a type I-II from Rothman and Manis, 2003
"""
def __init__(
self,
morphology=None,
decorator=None,
nach=None,
ttx=False,
species="guineapig",
modelType=None,
modelName=None,
debug=False,
):
"""
initialize a radial stellate (D-stellate) cell, using the default parameters for guinea pig from
R&M2003, as a type I-II cell.
Modifications to the cell can be made by calling methods below. These include:
* changing the sodium channel
* Changing "species" to mouse or cat (scales conductances)
* Shifting model type
Parameters
----------
morphology : string (default: None)
Name of a .hoc file representing the morphology. This file is used to constructe
an electrotonic (cable) model.
If None (default), then a "point" (really, single cylinder) 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 is inserted into the first soma section, and the
rest of the structure is "bare".
nach : string (default: None)
nach selects the type of sodium channel that will be used in the model. A channel mechanism
by that name must exist. A value of None will set the channel to a default for the model (nacn).
ttx : Boolean (default: False)
If ttx is True, then the sodium channel conductance is set to 0 everywhere in the cell.
This flag duplicates the effects of tetrodotoxin in the model. Currently, the flag is not implemented.
species: string (default 'guineapig')
species defines the pattern of ion channel densities that will be inserted, according to
prior measurements in various species. Note that
if a decorator function is specified, this argument is ignored as the decorator will
specify the channel density.
modelType: string (default: None)
modelType specifies the subtype of the cell model that will be used (e.g., "II", "II-I", etc).
modelType is passed to the decorator, or to species_scaling to adjust point (single cylinder) models.
debug: boolean (default: False)
When True, there will be multiple printouts of progress and parameters.
Returns
-------
Nothing
"""
super(DStellateRothman, self).__init__()
if modelType == None:
modelType = "I-II"
if species == "guineapig":
modelName = "RM03"
temp = 22.0
if nach == None:
nach = "nacn"
if species == "mouse":
temp = 34.0
if modelName is None:
modelName = "XM13"
if nach is None:
nach = "na"
self.debug = debug
# if modelType == None: # allow us to pass None to get the default
# modelType = 'I-II'
# if nach == None:
# nach = 'na'
self.status = {
"soma": True,
"axon": False,
"dendrites": False,
"pumps": False,
"na": nach,
"species": species,
"modelType": modelType,
"modelName": modelName,
"ttx": ttx,
"name": "DStellate",
"morphology": morphology,
"decorator": decorator,
"temperature": None,
}
self.i_test_range = {
"pulse": [(-0.3, 0.3, 0.03), (-0.05, 0.0, 0.005)]
} # set range for ic command test
self.vrange = [-75.0, -55.0]
self.spike_threshold = (
-40.0
) # matches threshold in released CNModel (set in base cell class)
if morphology is None:
"""
instantiate a basic soma-only ("point") model
"""
soma = h.Section(
name="DStellate_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 = ["klt", "kht", "ihvcn", "leak", nach]
for mech in self.mechanisms:
self.soma.insert(mech)
self.soma.ena = self.e_na
self.soma.ek = self.e_k
self.soma().leak.erev = self.e_leak
self.c_m = 0.9
self.set_soma_size_from_Cm(12.0)
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 self.debug:
print("<< D-stellate: JSR Stellate Type I-II cell model created >>")
def get_cellpars(self, dataset, species="guineapig", modelType="I-II"):
cellcap = data.get(
dataset, species=species, model_type=modelType, field="soma_Cap"
)
chtype = data.get(
dataset, species=species, model_type=modelType, field="na_type"
)
pars = Params(cap=cellcap, natype=chtype)
# pars.show()
if self.status["modelName"] == "RM03":
for g in [
"%s_gbar" % pars.natype,
"kht_gbar",
"klt_gbar",
"ka_gbar",
"ih_gbar",
"leak_gbar",
"leak_erev",
"ih_eh",
"e_k",
"e_na",
]:
pars.additem(
g, data.get(dataset, species=species, model_type=modelType, field=g)
)
if self.status["modelName"] == "XM13":
for g in [
"%s_gbar" % pars.natype,
"kht_gbar",
"klt_gbar",
"ka_gbar",
"ihvcn_gbar",
"leak_gbar",
"leak_erev",
"ih_eh",
"e_k",
"e_na",
]:
pars.additem(
g, data.get(dataset, species=species, model_type=modelType, field=g)
)
if self.status["modelName"] == "mGBC":
for g in [
"%s_gbar" % pars.natype,
"kht_gbar",
"klt_gbar",
"ka_gbar",
"ihvcn_gbar",
"leak_gbar",
"leak_erev",
]:
pars.additem(
g, data.get(dataset, species=species, model_type=modelType, field=g)
)
return pars
def species_scaling(self, species="guineapig", modelType="I-II", silent=True):
"""
Adjust all of the conductances and the cell size according to the species requested.
Parameters
----------
species : string (default: 'guineapig')
A string specifying the species used for scaling. Recognized values are
'mouse', 'guineapig', and 'cat' (cat is just a larger version of the guineapig)
modelType : string (default: 'I-II')
A string specifying the version of the model to use.
Current choices are 'I-II' (others need to be implemented)
silent : boolean (default: True)
Flag for printing debugging information.
"""
soma = self.soma
celltype = modelType
if species == "mouse":
# use conductance levels from Cao et al., J. Neurophys., 2007.
dataset = "XM13_channels"
self._valid_temperatures = (34.0,)
if self.status["temperature"] is None:
self.set_temperature(34.0)
self.c_m = 0.9
pars = self.get_cellpars(dataset, species=species, modelType=modelType)
self.set_soma_size_from_Cm(pars.cap)
self.status["na"] = pars.natype
# pars.show()
self.adjust_na_chans(soma, gbar=pars.na_gbar, sf=1.0)
soma().kht.gbar = nstomho(pars.kht_gbar, self.somaarea)
soma().klt.gbar = nstomho(pars.klt_gbar, self.somaarea)
# soma().ka.gbar = nstomho(pars.ka_gbar, self.somaarea)
soma().ihvcn.gbar = nstomho(pars.ihvcn_gbar, self.somaarea)
soma().ihvcn.eh = pars.ih_eh # Rodrigues and Oertel, 2006
soma().leak.gbar = nstomho(pars.leak_gbar, self.somaarea)
soma().leak.erev = pars.leak_erev
self.e_k = pars.e_k
self.e_na = pars.e_na
soma.ena = self.e_na
soma.ek = self.e_k
# soma().leak.erev = pars.leak_erev
self.axonsf = 0.5
elif species == "guineapig": # values from R&M 2003, Type II-I
dataset = "RM03_channels"
self.c_m = 0.9
self._valid_temperatures = (22.0, 38.0)
if self.status["temperature"] is None:
self.set_temperature(22.0)
sf = 1.0
if (
self.status["temperature"] == 38.0
): # adjust for 2003 model conductance levels at 38
sf = 3.03 # Q10 of 2, 22->38C. (p3106, R&M2003c)
self.i_test_range = {"pulse": (-0.3, 0.3, 0.03)}
self.vrange = [-75.0, -55.0]
pars = self.get_cellpars(dataset, species=species, modelType=modelType)
self.set_soma_size_from_Cm(pars.cap)
self.status["na"] = pars.natype
# pars.show()
self.adjust_na_chans(soma, gbar=pars.nacn_gbar, sf=sf)
soma().kht.gbar = nstomho(pars.kht_gbar, self.somaarea)
soma().klt.gbar = nstomho(pars.klt_gbar, self.somaarea)
# soma().ka.gbar = nstomho(pars.ka_gbar, self.somaarea)
soma().ihvcn.gbar = nstomho(pars.ih_gbar, self.somaarea)
soma().leak.gbar = nstomho(pars.leak_gbar, self.somaarea)
soma().leak.erev = pars.leak_erev
self.axonsf = 0.5
else:
raise ValueError(
"Species %s or species-modelType %s is not recognized for D-Stellate cells"
% (species, modelType)
)
self.status["species"] = species
self.status["modelType"] = modelType
self.check_temperature()
# self.cell_initialize(showinfo=False)
if not silent:
print("set cell as: ", species)
print(" with Vm rest = %6.3f" % self.vm0)
def adjust_na_chans(self, soma, sf=1.0, gbar=1000.0):
"""
adjust the sodium channel conductance
Parameters
----------
soma : soma object (no default)
soma object whose sodium channel complement will have it's
conductances adjusted depending on the channel type
gbar : float (default: 1000.)
The conductance to be set for the sodium channel
debug : boolean (default: False)
Flag for printing the conductance value and Na channel model
Returns
-------
Nothing
"""
if self.status["ttx"]:
gnabar = 0.0
else:
gnabar = nstomho(gbar, self.somaarea) * sf
nach = self.status["na"]
if nach == "jsrna":
soma().jsrna.gbar = gnabar
soma.ena = self.e_na
if self.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 self.debug:
print("bushy using inva11")
print("nav11 gbar: ", soma().nav11.gbar)
elif nach == "na":
soma().na.gbar = gnabar
soma.ena = self.e_na
if self.debug:
print("na gbar: ", soma().na.gbar)
elif nach == "nacn":
soma().nacn.gbar = gnabar
soma.ena = self.e_na
if self.debug:
print("nacn gbar: ", soma().nacn.gbar)
else:
raise ValueError(
"Dstellate setting Na channels: channel %s not known" % nach
)
def add_axon(self):
"""
Add a default axon from the generic cell class to the bushy cell (see cell class).
"""
Cell.add_axon(self, self.soma, self.somaarea, self.c_m, self.R_a, self.axonsf)
def add_dendrites(self):
"""
Add simple unbranched dendrites to basic Rothman Type I-II model.
The dendrites have some kht and ih current
"""
cs = False # not implemented outside here - internal Cesium.
nDend = range(4) # these will be simple, unbranced, N=4 dendrites
dendrites = []
for i in nDend:
dendrites.append(h.Section(cell=self.soma))
for i in nDend:
dendrites[i].connect(self.soma)
dendrites[i].L = 300 # length of the dendrite (not tapered)
dendrites[i].diam = 1.25 # dendrite diameter
dendrites[i].nseg = 21 # # segments in dendrites
dendrites[i].Ra = 150 # ohm.cm
dendrites[i].insert("kht")
if cs is False:
dendrites[i]().kht.gbar = 0.005 # a little Ht
else:
dendrites[i]().kht.gbar = 0.0
dendrites[i].insert("leak") # leak
dendrites[i]().leak.gbar = 0.0001
dendrites[i].insert("ihvcn") # some H current
dendrites[i]().ihvcn.gbar = 0.0 # 0.001
dendrites[i]().ihvcn.eh = -43.0
self.maindend = dendrites
self.status["dendrites"] = True
self.add_section(self.maindend, "maindend")
class DummyDStellate(DStellate):
""" DStellate class with no cell body; this cell only replays a predetermined
spike train. Useful for testing, or replacing spike trains to determine
the importance of spike structures within a network.
"""
def __init__(self, cf=None, species="mouse"):
"""
Parameters
----------
cf : float (default: None)
Required: the characteristic frequency for the DStellate
Really just for reference.
"""
DStellate.__init__(self)
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": species,
"modelType": "Dummy",
"modelName": "DummyDStellate",
"ttx": None,
"name": "DummyDStellate",
"morphology": None,
"decorator": None,
"temperature": None,
}
print("<< DStellate: Dummy DStellate Cell created >>")
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)
class DStellateEager(DStellate):
"""
This is a model of the VCN D-Stellate cells as proposed by
Eager, M.A., Grayden, D.B., Burkitt, A.N., and Meffin, H.,
"A neural circuit model of the ventral cochlear nucleus",
Internet:
http://citeseerx.ist.pus.edu/viewdoc/download?doi=10.1.79.9620.pdf&rep
=rep&type=pdf
also cited as:
Proceedings of the 10th Australian International Conference on
Speech Science and Technology, pp. 539-544, 2004.
It is based on the Rothman and Manis (2003c) model,
with small modifications.
Their model includes dendrites and an axon, which are added in this version
"""
def __init__(
self, nach="na", ttx=False, species="guineapig", modelType="I-II", debug=False
):
"""
Initialize the VCN D-stellate model of Eager et al. Some model parameters may be modified.
Parameters
----------
nach : string (default: 'na')
Set the sodium channel model. Choices are 'na', 'nav11', 'jsrna'
ttx : boolean (default: False)
ttx sets the sodium channel conductance to 0
species : string (default: 'guineapig')
species to use for conductance scaling
modelType : string (default: 'I-II')
RM03 model type to use for conductances.
debug : boolean (default: False)
Flag to use to enable print statements for debugging purposes.
"""
super(DStellateEager, self).__init__()
self.status = {
"soma": True,
"axon": False,
"dendrites": False,
"pumps": False,
"na": nach,
"species": species,
"modelType": modelType,
"ttx": ttx,
"name": "DStellateEager",
}
self.i_test_range = (-0.25, 0.25, 0.025) # set range for ic command test
soma = h.Section(name="DStellateEager_Soma_%x" % id(self)) # one compartment
soma.nseg = 1
if nach in ["nacn", "na"]:
soma.insert("na")
elif nach == "nav11":
soma.insert("nav11")
elif nach == "jsrna":
soma.insert("jsrna")
else:
raise ValueError("Sodium channel %s in type 1 cell not known" % nach)
self.debug = debug
soma.insert("kht")
soma.insert("klt")
soma.insert("ihvcn")
soma.insert("leak")
soma.ek = self.e_k
soma().leak.erev = self.e_leak
self.mechanisms = ["kht", "klt", "ihvcn", "leak", nach]
self.add_section(soma, "soma")
self.species_scaling(
silent=False, species=species, modelType=modelType
) # set the default type II cell parameters
self.add_axon() # must follow species scaling so that area parameters are available
self.add_dendrites() # similar for dendrites
self.save_all_mechs() # save all mechanisms inserted, location and gbar values...
self.get_mechs(soma)
if self.debug:
print("<< D-stellateEager: Eager DStellate Type I-II cell model created >>")
def species_scaling(self, species="guineapig", modelType="I-II", silent=True):
"""
Adjust all of the conductances and the cell size according to the species requested.
Parameters
----------
species : string (default: 'guineapig')
A string specifying the species used for scaling. Recognized values are
'mouse', 'guineapig', and 'cat' (cat is just a larger version of the guineapig)
modelType : string (default: 'I-II')
A string specifying the version of the model to use.
Current choices are 'I-II' (others need to be implemented)
silent : boolean (default: True)
Flag for printing debugging information.
"""
soma = self.soma
if species == "mouse" and modelType == "I-II":
# use conductance levels from Cao et al., J. Neurophys., 2007.
self.set_soma_size_from_Cm(25.0)
self.adjust_na_chans(soma, gbar=800.0)
soma().kht.gbar = nstomho(150.0, self.somaarea)
soma().klt.gbar = nstomho(20.0, self.somaarea)
soma().ihvcn.gbar = nstomho(2.0, self.somaarea)
soma().ihvcn.eh = -43 # Rodrigues and Oertel, 2006
soma().leak.gbar = nstomho(2.0, self.somaarea)
self.axonsf = 0.5
elif (
species == "guineapig" and modelType == "I-II"
): # values from R&M 2003, Type II-I
self.set_soma_size_from_Diam(25.0)
self.adjust_na_chans(soma, gbar=1000.0 * 0.75)
soma().kht.gbar = 0.02 # nstomho(150.0, self.somaarea)
soma().klt.gbar = 0.005 # nstomho(20.0, self.somaarea)
soma().ihvcn.gbar = 0.0002 # nstomho(2.0, self.somaarea)
soma().leak.gbar = 0.0005 # nstomho(2.0, self.somaarea)
self.axonsf = 1.0
elif (
species == "cat" and modelType == "I=II"
): # a cat is a big guinea pig Type I
self.set_soma_size_from_Cm(35.0)
self.adjust_na_chans(soma)
soma().kht.gbar = nstomho(150.0, self.somaarea)
soma().klt.gbar = nstomho(20.0, self.somaarea)
soma().ihvcn.gbar = nstomho(2.0, self.somaarea)
soma().leak.gbar = nstomho(2.0, self.somaarea)
self.axonsf = 1.0
else:
raise ValueError(
"Species %s or species-type %s is not recognized for D-StellateEager cells"
% (species, type)
)
self.status["species"] = species
self.status["type"] = modelType
self.cell_initialize(showinfo=True)
if not silent:
print(" set cell as: ", species)
print(" with Vm rest = %6.3f" % self.vm0)
def adjust_na_chans(self, soma, gbar=1000.0):
"""
adjust the sodium channel conductance
Parameters
----------
soma : soma object (no default)
soma object whose sodium channel complement will have it's
conductances adjusted depending on the channel type
gbar : float (default: 1000.)
The conductance to be set for the sodium channel
Returns
-------
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 self.debug:
print("using jsrna with gbar: ", soma().jsrna.gbar)
elif nach == "nav11":
soma().nav11.gbar = gnabar * 0.5
soma.ena = self.e_na
soma().nav11.vsna = 4.3
if self.debug:
print("using inva11 with gbar:", soma().na.gbar)
print("nav11 gbar: ", soma().nav11.gbar)
elif nach == "na":
soma().na.gbar = gnabar
soma.ena = self.e_na
if self.debug:
print("using na with gbar: ", soma().na.gbar)
elif nach == "nach":
soma().nach.gbar = gnabar
soma.ena = self.e_na
if self.debug:
print(("uwing nacn with gbar: ", soma().nacn.gbar))
else:
raise ValueError(
"DstellateEager setting Na channels: channel %s not known" % nach
)
# print soma().na.gbar
def add_axon(self):
"""
Adds an axon to the Eager. et al model
Cell.add_axon(self, nodes=1, c_m=self.c_m, R_a=self.R_a, axonsf=self.axonsf, dia=3.0, len=70, seg=2)
The Eager et al model just uses one cable, 70 microns long and 3 microns in dameter.
Parameters
----------
None
Returns
-------
Nothing
"""
naxons = 1
axon = []
for i in range(naxons):
axon.append(h.Section(cell=self.soma))
for i in range(naxons):
axon[i].connect(self.soma)
axon[i].L = 70
axon[i].diam = 3.0
axon[i].Ra = 500
axon[i].cm = 0.9
axon[i].nseg = 2
axon[i].insert("kht")
axon[i].insert("klt")
axon[i].insert("ihvcn")
axon[i].insert("leak")
axon[i].insert("na")
axon[i].ek = self.e_k
axon[i].ena = self.e_na
axon[i]().leak.erev = self.e_leak
axon[i]().na.gbar = 0.5
axon[i]().klt.gbar = 0.005
axon[i]().kht.gbar = 0.02
axon[i]().ihvcn.gbar = 0.0002
axon[i]().leak.gbar = 0.0005
self.status["axon"] = True
self.add_section(axon, "axon")
def add_dendrites(self):
"""
Adds dendrites to the Eager model. The Eager model uses simple passive dendrites.
Parameters
----------
None
Returns
-------
Nothing
"""
nDend = range(2) # these will be simple, unbranced, N=4 dendrites
dendrites = []
for i in nDend:
dendrites.append(h.Section(cell=self.soma))
for i in nDend:
dendrites[i].connect(self.soma)
dendrites[i].L = 1100 # length of the dendrite (not tapered)
dendrites[i].diam = 3.5 # dendrite diameter
dendrites[i].nseg = 5 # # segments in dendrites
dendrites[i].Ra = 1500 # ohm.cm
dendrites[i].insert("leak") # leak
dendrites[i]().leak.gbar = 0.00025
dendrites[i]().leak.erev = self.e_leak
self.maindend = dendrites
self.status["dendrites"] = True
self.add_section(self.maindend, "maindend")

47
cnmodel/cells/hh.py Normal file
View File

@@ -0,0 +1,47 @@
from __future__ import print_function
from neuron import h
import neuron as nrn
from ..util import nstomho
from .cell import Cell
__all__ = ["HH"]
class HH(Cell):
"""
Standard Hodgkin-Huxley mechanisms from NEURON
"""
def __init__(self, debug=False, message=None):
super(HH, self).__init__()
soma = h.Section(
name="HH_Soma_%x" % id(self)
) # one compartment of about 29000 um2
v_potassium = -80 # potassium reversal potential
v_sodium = 50 # sodium reversal potential
c_m = 1.0
scalefactor = 1.0 # This determines the relative size of the cell
rinsf = 1.0 # input resistance adjustment (also current...)
totcap = 20.0 # scalefactor * 1.0 # cap in pF for cell
effcap = totcap # sometimes we change capacitance - that's effcap
somaarea = totcap * 1e-6 / c_m # pf -> uF, cm = 1uf/cm^2 nominal
lstd = 1e4 * ((somaarea / 3.14159) ** 0.5) # convert from cm to um
soma.nseg = 1
soma.diam = lstd
soma.L = lstd
seg = soma
seg.insert("hh")
seg.insert("pas")
if debug:
if message is None:
print("<< Standard HH model created >>")
else:
print(message)
self.add_section(soma, "soma")
self.vm0 = -67.536

View File

@@ -0,0 +1,516 @@
from __future__ import print_function
from neuron import h
from .cell import Cell
# from .. import synapses
from ..util import nstomho
from ..util import Params
import numpy as np
from .. import data
__all__ = ["MSO"]
class MSO(Cell):
type = "mso"
@classmethod
def create(cls, model="MSO-principal", **kwds):
if model == "MSO-principal":
return MSOPrincipal(**kwds)
else:
raise ValueError("MSO cell model %s is unknown", model)
def make_psd(self, terminal, psd_type, **kwds):
"""
Connect a presynaptic terminal to one post section at the specified location, with the fraction
of the "standard" conductance determined by gbar.
The default condition is designed to pass the unit test (loc=0.5)
Parameters
----------
terminal : Presynaptic terminal (NEURON object)
psd_type : either simple or multisite PSD for MSO cell
kwds: dictionary of options.
Two are currently handled:
postsite : expect a list consisting of [sectionno, location (float)]
AMPAScale : float to scale the ampa currents
"""
if (
"postsite" in kwds
): # use a defined location instead of the default (soma(0.5)
postsite = kwds["postsite"]
loc = postsite[1] # where on the section?
uname = (
"sections[%d]" % postsite[0]
) # make a name to look up the neuron section object
post_sec = self.hr.get_section(uname) # Tell us where to put the synapse.
else:
loc = 0.5
post_sec = self.soma
if psd_type == "simple":
return self.make_exp2_psd(post_sec, terminal, loc=loc)
elif psd_type == "multisite":
if terminal.cell.type == "bushy":
# Max conductances for the glu mechanisms are calibrated by
# running `synapses/tests/test_psd.py`. The test should fail
# if these values are incorrect
self.AMPAR_gmax = (
data.get(
"bushy_synapse",
species=self.species,
post_type=self.type,
field="AMPAR_gmax",
)
* 1e3
)
self.NMDAR_gmax = (
data.get(
"bushy_synapse",
species=self.species,
post_type=self.type,
field="NMDAR_gmax",
)
* 1e3
)
self.Pr = data.get(
"bushy_synapse",
species=self.species,
post_type=self.type,
field="Pr",
)
# adjust gmax to correct for initial Pr
self.AMPAR_gmax = self.AMPAR_gmax / self.Pr
self.NMDAR_gmax = self.NMDAR_gmax / self.Pr
if "AMPAScale" in kwds: # normally, this should not be done!
self.AMPAR_gmax = (
self.AMPAR_gmax * kwds["AMPAScale"]
) # allow scaling of AMPA conductances
if "NMDAScale" in kwds:
self.NMDAR_gmax = self.NMDAR_gmax * kwds["NMDAScale"] # and NMDA...
return self.make_glu_psd(
post_sec, terminal, self.AMPAR_gmax, self.NMDAR_gmax, loc=loc
)
else:
raise TypeError(
"Cannot make PSD for %s => %s" % (terminal.cell.type, self.type)
)
else:
raise ValueError("Unsupported psd type %s" % psd_type)
class MSOPrincipal(MSO):
"""
VCN MSO cell models.
Using Rothman and Manis, 2003abc (Type II)
MSO principal cell type
"""
def __init__(
self,
morphology=None,
decorator=None,
nach=None,
ttx=False,
species="guineapig",
modelType=None,
debug=False,
temperature=None,
):
"""
Create a MSO principal cell, using the default parameters for guinea pig from
R&M2003, as a type II cell.
Additional modifications to the cell can be made by calling methods below.
Parameters
----------
morphology : string (default: None)
Name of a .hoc file representing the morphology. This file is used to constructe
an electrotonic (cable) model.
If None (default), then a "point" (really, single cylinder) 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 is inserted into the first soma section, and the
rest of the structure is "bare".
nach : string (default: None)
nach selects the type of sodium channel that will be used in the model. A channel mechanism
by that name must exist. The default channel is set to 'nacn' (R&M03)
temperature : float (default: 22)
temperature to run the cell at.
ttx : Boolean (default: False)
If ttx is True, then the sodium channel conductance is set to 0 everywhere in the cell.
This flag duplicates the effects of tetrodotoxin in the model. Currently, the flag is not implemented.
temperature : float (default: None, sets to model default of 22)
temperature (deg C) to run the cell at. Must be a valid temperature for the model.
species: string (default 'guineapig')
species defines the pattern of ion channel densities that will be inserted, according to
prior measurements in various species. Note that
if a decorator function is specified, this argument is ignored as the decorator will
specify the channel density.
modelType: string (default: None)
modelType specifies the subtype of the cell model that will be used (e.g., "II", "II-I", etc).
modelType is passed to the decorator, or to species_scaling to adjust point (single cylinder) models.
debug: boolean (default: False)
When True, there will be multiple printouts of progress and parameters.
Returns
-------
Nothing
"""
super(MSO, self).__init__()
self.i_test_range = {
"pulse": (-1, 1, 0.05)
} # note that this gets reset with decorator according to channels
# Changing the default values will cause the unit tests to fail!
if modelType == None:
modelType = "principal"
if nach == None and species == "guineapig":
nach = "na"
if nach == None and species == "mouse":
nach = "na"
self.i_test_range = {"pulse": (-1, 1.2, 0.05)}
self.status = {
"soma": True,
"axon": False,
"dendrites": False,
"pumps": False,
"hillock": False,
"initialsegment": False,
"myelinatedaxon": False,
"unmyelinatedaxon": False,
"na": nach,
"species": species,
"modelType": modelType,
"ttx": ttx,
"name": "MSO",
"morphology": morphology,
"decorator": decorator,
"temperature": temperature,
}
self.spike_threshold = -40
self.vrange = [-70.0, -55.0] # set a default vrange for searching for rmp
print("model type, species: ", modelType, species, nach)
if morphology is None:
"""
instantiate a basic soma-only ("point") model
"""
print("<< MSO model: Creating point principal cell >>")
soma = h.Section(
name="MSO_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
"""
print(
"<< MSO principal cell model: Creating cell with morphology from %s >>"
% morphology
)
self.set_morphology(morphology_file=morphology)
# decorate the morphology with ion channels
if decorator is None: # basic model, only on the soma
self.mechanisms = ["klt", "kht", "ihvcn", "leak", nach]
for mech in self.mechanisms:
self.soma.insert(mech)
self.soma.ena = self.e_na
self.soma.ek = self.e_k
self.soma().ihvcn.eh = self.e_h
self.soma().leak.erev = self.e_leak
self.c_m = 0.9
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(" << Created cell >>")
def get_cellpars(self, dataset, species="guineapig", celltype="principal"):
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(cap=cellcap, natype=chtype)
for g in ["soma_kht_gbar", "soma_klt_gbar", "soma_ih_gbar", "soma_leak_gbar"]:
pars.additem(
g, data.get(dataset, species=species, cell_type=celltype, field=g)
)
return pars
def species_scaling(self, species="guineapig", modelType="principal", silent=True):
"""
Adjust all of the conductances and the cell size according to the species requested.
This scaling should be used ONLY for point models, as no other compartments
are scaled.
This scaling routine also sets the temperature for the model to a default value. Some models
can be run at multiple temperatures, and so a default from one of the temperatures is used.
The calling cell.set_temperature(newtemp) will change the conductances and reinitialize
the cell to the new temperature settings.
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, cat, guineapig
modelType: string (default: 'principal')
definition of model type from RM03 models, principal cell for mso
silent : boolean (default: True)
run silently (True) or verbosely (False)
"""
# print '\nSpecies scaling: %s %s' % (species, type)
knownspecies = ["guineapig"]
soma = self.soma
if modelType == "principal":
celltype = (
"MSO-principal"
) # There are other possiblities in the literature - this is just the main one
else:
raise ValueError("model type not recognized")
if species == "guineapig":
print(
" Setting conductances for guinea pig %s MSO cell, based on Rothman and Manis, 2003 bushy cell"
% modelType
)
self._valid_temperatures = (22.0, 38.0)
if self.status["temperature"] is None:
self.status["temperature"] = 22.0
self.i_test_range = {"pulse": (-0.4, 0.4, 0.02)}
sf = 1.0
if (
self.status["temperature"] == 38.0
): # adjust for 2003 model conductance levels at 38
sf = 2 # Q10 of 2, 22->38C. (p3106, R&M2003c)
# note that kinetics are scaled in the mod file.
dataset = "MSO_principal_channels"
pars = self.get_cellpars(dataset, species=species, celltype=celltype)
self.set_soma_size_from_Cm(pars.cap)
self.status["na"] = pars.natype
self.adjust_na_chans(soma, sf=sf)
soma().kht.gbar = nstomho(pars.soma_kht_gbar, self.somaarea)
soma().klt.gbar = nstomho(pars.soma_klt_gbar, self.somaarea)
soma().ihvcn.gbar = nstomho(pars.soma_ih_gbar, self.somaarea)
soma().leak.gbar = nstomho(pars.soma_leak_gbar, self.somaarea)
self.axonsf = 0.57
else:
errmsg = (
'Species "%s" or model type "%s" is not recognized for MSO cells.'
% (species, modelType)
)
errmsg += "\n Valid species are: \n"
for s in knownspecies:
errmsg += " %s\n" % s
errmsg += "-" * 40
raise ValueError(errmsg)
self.status["species"] = species
self.status["modelType"] = modelType
self.check_temperature()
# self.cell_initialize(vrange=self.vrange) # no need to do this just yet.
if not silent:
print(" set cell as: ", species)
print(" with Vm rest = %6.3f" % self.vm0)
def channel_manager(self, modelType="MSO-principal"):
"""
This routine defines channel density maps and distance map patterns
for each type of compartment in the cell. The maps
are used by the ChannelDecorator class (specifically, its private
\_biophys function) to decorate the cell membrane.
These settings are only used if the decorator is called; otherwise
for point cells, the species_scaling routine defines the channel
densities.
Parameters
----------
modelType : string (default: 'RM03')
A string that defines the type of the model. Currently, only 1 type is implemented:
RM03: Rothman and Manis, 2003 somatic densities based on guinea pig bushy cell
Returns
-------
Nothing
Notes
-----
This routine defines the following variables for the class:
* conductances (gBar)
* a channelMap (dictonary of channel densities in defined anatomical compartments)
* a current injection range for IV's (used for testing)
* a distance map, which defines how each conductance in a selected compartment
changes with distance from the soma. The current implementation includes both
linear and exponential gradients,
the minimum conductance at the end of the gradient, and the space constant or
slope for the gradient.
"""
self.c_m = 1e-6 # default in units of F/cm^2
if modelType == "MSO-principal":
#
# Create a model based on the Rothman and Manis 2003 conductance set from guinea pig
#
self.c_m = 0.9e-6 # default in units of F/cm^2
totcap = 12.0e-12 # in units of F, from Rothman and Manis, 2003.
refarea = totcap / self.c_m # area is in cm^2
# MSO Rothman-Manis, guinea pig type II
# model gave cell conductance in nS, but we want S/cm^2 for NEURON
# so conversion is 1e-9*nS = uS, and refarea is already in cm2
self._valid_temperatures = (22.0, 38.0)
sf = 1.0
if self.status["temperature"] == None:
self.status["temperature"] = 22.0
if self.status["temperature"] == 38:
sf = 3.03
self.gBar = Params(
nabar=sf * 1000.0e-9 / refarea,
khtbar=sf * 150.0e-9 / refarea,
kltbar=sf * 200.0e-9 / refarea,
ihbar=sf * 20.0e-9 / refarea,
leakbar=sf * 2.0e-9 / refarea,
)
print("MSO principal channels gbar:\n", self.gBar.show())
self.channelMap = {
"axon": {
"nacn": self.gBar.nabar,
"klt": self.gBar.kltbar,
"kht": self.gBar.khtbar,
"ihvcn": 0.0,
"leak": self.gBar.leakbar / 2.0,
},
"hillock": {
"nacn": self.gBar.nabar,
"klt": self.gBar.kltbar,
"kht": self.gBar.khtbar,
"ihvcn": 0.0,
"leak": self.gBar.leakbar,
},
"initseg": {
"nacn": self.gBar.nabar,
"klt": self.gBar.kltbar,
"kht": self.gBar.khtbar,
"ihvcn": self.gBar.ihbar / 2.0,
"leak": self.gBar.leakbar,
},
"soma": {
"nacn": self.gBar.nabar,
"klt": self.gBar.kltbar,
"kht": self.gBar.khtbar,
"ihvcn": self.gBar.ihbar,
"leak": self.gBar.leakbar,
},
"dend": {
"nacn": self.gBar.nabar,
"klt": self.gBar.kltbar * 0.5,
"kht": self.gBar.khtbar * 0.5,
"ihvcn": self.gBar.ihbar / 3.0,
"leak": self.gBar.leakbar * 0.5,
},
"apic": {
"nacn": self.gBar.nabar,
"klt": self.gBar.kltbar * 0.2,
"kht": self.gBar.khtbar * 0.2,
"ihvcn": self.gBar.ihbar / 4.0,
"leak": self.gBar.leakbar * 0.2,
},
}
# self.irange = np.linspace(-1., 1., 21)
self.distMap = {
"dend": {
"klt": {"gradient": "linear", "gminf": 0.0, "lambda": 100.0},
"kht": {"gradient": "linear", "gminf": 0.0, "lambda": 100.0},
"nacn": {"gradient": "exp", "gminf": 0.0, "lambda": 100.0},
}, # linear with distance, gminf (factor) is multiplied by gbar
"apic": {
"klt": {"gradient": "linear", "gminf": 0.0, "lambda": 100.0},
"kht": {"gradient": "linear", "gminf": 0.0, "lambda": 100.0},
"nacn": {"gradient": "exp", "gminf": 0.0, "lambda": 100.0},
}, # gradients are: flat, linear, exponential
}
else:
raise ValueError("model type %s is not implemented" % modelType)
self.check_temperature()
def adjust_na_chans(self, soma, sf=1.0, gbar=1000.0, debug=False):
"""
adjust the sodium channel conductance
Parameters
----------
soma : neuron section object
A soma object whose sodium channel complement will have its
conductances adjusted depending on the channel type
gbar : float (default: 1000.)
The maximal conductance for the sodium channel
debug : boolean (false):
Verbose printing
Returns
-------
Nothing :
"""
if self.status["ttx"]:
gnabar = 0.0
else:
gnabar = nstomho(gbar, self.somaarea) * sf
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
soma.ena = 50 # self.e_na
# print('gnabar: ', soma().nav11.gbar, ' vs: 0.0192307692308')
soma().nav11.vsna = 4.3
if debug:
print("MSO using inva11")
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 MSO cells", nach)

718
cnmodel/cells/octopus.py Normal file
View File

@@ -0,0 +1,718 @@
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 data
"""
Original hoc code from RMmodel.hoc
// including the "Octopus" cell:
proc set_Type2o() {
gbar_na = nstomho(1000)
gbar_kht = nstomho(150)
gbar_klt = nstomho(600)
gbar_ka = nstomho(0)
gbar_ih = nstomho(0)
gbar_hcno = nstomho(40)
gbar_leak = nstomho(2)
model = 6
modelname = "Type IIo (Octopus)"
vm0 = -66.67
}
"""
__all__ = ["Octopus", "OctopusRothman", "OctopusSpencer"]
class Octopus(Cell):
type = "octopus"
@classmethod
def create(cls, modelType="RM03", **kwds):
if modelType in ["RM03", "II-o"]:
return OctopusRothman(**kwds)
elif modelType == "Spencer":
return OctopusSpencer(**kwds)
else:
raise ValueError("Octopus cell type %s is unknown" % modelType)
def make_psd(self, terminal, psd_type, **kwds):
"""
Connect a presynaptic terminal to one post section at the specified location, with the fraction
of the "standard" conductance determined by gbar.
The default condition is to try to pass the default unit test (loc=0.5)
Parameters
----------
terminal : Presynaptic terminal (NEURON object)
psd_type : either simple or multisite PSD for bushy cell
kwds: dict of options. Two are currently handled:
postsize : expect a list consisting of [sectionno, location (float)]
AMPAScale : float to scale the ampa currents
"""
if (
"postsite" in kwds
): # use a defined location instead of the default (soma(0.5)
postsite = kwds["postsite"]
loc = postsite[1] # where on the section?
uname = (
"sections[%d]" % postsite[0]
) # make a name to look up the neuron section object
post_sec = self.hr.get_section(uname) # Tell us where to put the synapse.
else:
loc = 0.5
post_sec = self.soma
if psd_type == "simple":
if terminal.cell.type in ["sgc"]:
weight = data.get(
"%s_synapse" % terminal.cell.type,
species=self.species,
post_type=self.type,
field="weight",
)
tau1 = data.get(
"%s_synapse" % terminal.cell.type,
species=self.species,
post_type=self.type,
field="tau1",
)
tau2 = data.get(
"%s_synapse" % terminal.cell.type,
species=self.species,
post_type=self.type,
field="tau2",
)
erev = data.get(
"%s_synapse" % terminal.cell.type,
species=self.species,
post_type=self.type,
field="erev",
)
return self.make_exp2_psd(
post_sec,
terminal,
weight=weight,
loc=loc,
tau1=tau1,
tau2=tau2,
erev=erev,
)
else:
raise TypeError(
"Cannot make simple PSD for %s => %s"
% (terminal.cell.type, self.type)
)
elif psd_type == "multisite":
if terminal.cell.type == "sgc":
# Max conductances for the glu mechanisms are calibrated by
# running `synapses/tests/test_psd.py`. The test should fail
# if these values are incorrect
self.AMPAR_gmax = (
data.get(
"sgc_synapse",
species=self.species,
post_type=self.type,
field="AMPAR_gmax",
)
* 1e3
)
self.NMDAR_gmax = (
data.get(
"sgc_synapse",
species=self.species,
post_type=self.type,
field="NMDAR_gmax",
)
* 1e3
)
self.Pr = data.get(
"sgc_synapse", species=self.species, post_type=self.type, field="Pr"
)
# adjust gmax to correct for initial Pr
self.AMPAR_gmax = self.AMPAR_gmax / self.Pr
self.NMDAR_gmax = self.NMDAR_gmax / self.Pr
# AMPA_gmax = 3.314707700918133*1e3 # factor of 1e3 scales to pS (.mod mechanisms) from nS.
# NMDA_gmax = 0.4531929783503451*1e3
if "AMPAScale" in kwds:
self.AMPAR_gmax = (
self.AMPAR_gmax * kwds["AMPAScale"]
) # allow scaling of AMPA conductances
if "NMDAScale" in kwds:
self.NMDAR_gmax = self.NMDAR_gmax * kwds["NMDAScale"]
return self.make_glu_psd(
post_sec, terminal, self.AMPAR_gmax, self.NMDAR_gmax, loc=loc
)
elif terminal.cell.type == "dstellate":
return self.make_gly_psd(post_sec, terminal, psdtype="glyslow", loc=loc)
else:
raise TypeError(
"Cannot make PSD for %s => %s" % (terminal.cell.type, self.type)
)
else:
raise ValueError("Unsupported psd type %s" % psd_type)
class OctopusRothman(Octopus, Cell):
"""
VCN octopus cell model (point cell).
Rothman and Manis, 2003abc (Type II, with high gklt and hcno - octopus cell h current).
"""
def __init__(
self,
morphology=None,
decorator=None,
nach=None,
ttx=False,
species="guineapig",
modelType=None,
debug=False,
):
"""
initialize the octopus cell, using the default parameters for guinea pig from
R&M2003, as a type II cell with modified conductances.
Modifications to the cell can be made by calling methods below.
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: None)
nach selects the type of sodium channel that will be used in the model. A channel mechanism
by that name must exist. None implies the default channel (jsrna for this model).
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 (e.g., "II", "II-I", etc).
modelType is passed to the decorator, or to species_scaling to adjust point models.
debug: boolean (default: False)
debug is a boolean flag. When set, there will be multiple printouts of progress and parameters.
Returns
-------
Nothing
"""
super(OctopusRothman, self).__init__()
if modelType == None:
modelType = "II-o"
if nach == None and species == "guineapig":
nach = "jsrna"
if nach == None and species == "mouse":
nach = "nacn"
self.status = {
"soma": True,
"axon": False,
"dendrites": False,
"pumps": False,
"na": nach,
"species": species,
"modelType": modelType,
"ttx": ttx,
"name": "Octopus",
"morphology": morphology,
"decorator": decorator,
"temperature": None,
}
self.i_test_range = {"pulse": (-4.0, 4.0, 0.2)}
self.spike_threshold = -50
self.vrange = [-70.0, -57.0] # set a default vrange for searching for rmp
if morphology is None:
"""
instantiate a basic soma-only ("point") model
"""
soma = h.Section(
name="Octopus_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.e_leak = -73.0 # from McGinley et al., 2016
self.e_h = -38.0 # from McGinley et al.
self.R_a = 195 # McGinley et al.
if self.status["species"] == "mouse":
self.mechanisms = ["klt", "kht", "hcnobo", "leak", nach]
else:
self.mechanisms = ["klt", "kht", "ihvcn", "leak", nach]
for mech in self.mechanisms:
self.soma.insert(mech)
self.soma.ek = self.e_k
self.soma.ena = self.e_na
if self.status["species"] == "mouse":
self.soma().hcnobo.eh = self.e_h
else:
self.soma().ihvcn.eh = self.e_h
self.soma().leak.erev = self.e_leak
self.soma.Ra = self.R_a
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("<< octopus: octopus cell model created >>")
# print 'Cell created: ', self.status
def species_scaling(self, species="guineapig", modelType="II-o", silent=True):
"""
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 guineapig
modelType: string (default: 'II-o')
definition of model type from RM03 models, currently limited to type II-o
silent : boolean (default: True)
run silently (True) or verbosely (False)
"""
soma = self.soma
if species == "guineapig" and modelType == "II-o":
self.c_m = 0.9
self.set_soma_size_from_Cm(25.0)
self._valid_temperatures = (22.0, 38.0)
if self.status["temperature"] is None:
self.set_temperature(22.0)
sf = 1.0
if (
self.status["temperature"] == 38.0
): # adjust for 2003 model conductance levels at 38
sf = 3.03 # Q10 of 2, 22->38C. (p3106, R&M2003c)
# note that kinetics are scaled in the mod file.
# self.print_soma_info()
self.adjust_na_chans(soma, sf=sf)
soma().kht.gbar = sf * nstomho(150.0, self.somaarea) # 6.1 mmho/cm2
soma().klt.gbar = sf * nstomho(
1000.0, self.somaarea
) # 40.7 mmho/cm2 3195?
soma().ihvcn.gbar = sf * nstomho(
30.0, self.somaarea
) # 7.6 mmho/cm2, cf. Bal and Oertel, Spencer et al. 25 u dia cell 40ns?
soma().leak.gbar = sf * nstomho(2.0, self.somaarea)
self.axonsf = 1.0
elif species == "mouse" and modelType == "II-o":
self.set_soma_size_from_Cm(25.0)
self._valid_temperatures = (34.0,)
if self.status["temperature"] is None:
self.set_temperature(34.0)
# self.print_soma_info()
self.adjust_na_chans(soma, gbar=3000.0)
soma().kht.gbar = nstomho(150.0, self.somaarea) # 6.1 mmho/cm2
soma().klt.gbar = nstomho(3196.0, self.somaarea) # 40.7 mmho/cm2
soma().hcnobo.gbar = nstomho(
40.0, self.somaarea
) # 7.6 mmho/cm2, cf. Bal and Oertel, Spencer et al. 25 u dia cell
soma().leak.gbar = nstomho(2.0, self.somaarea)
self.axonsf = 1.0
else:
raise ValueError(
'Species "%s" or species-type "%s" is not recognized for octopus cells'
% (species, type)
)
self.status["species"] = species
self.status["modelType"] = modelType
# self.cell_initialize(showinfo=True)
self.check_temperature()
if not silent:
print("set cell as: ", species)
print(" with Vm rest = %6.3f" % self.vm0)
def adjust_na_chans(self, soma, sf=1.0, gbar=1000.0, debug=False):
"""
adjust the sodium channel conductance
Parameters
----------
soma : neuron section object
a soma object whose sodium channel complement will have it's
conductances adjusted depending on the channel type
gbar : float (default: 1000.)
the maximal conductance for the sodium channel
debug : boolean (false):
verbose printing
Returns
-------
Nothing
"""
if self.status["ttx"]:
gnabar = 0.0
else:
gnabar = sf * nstomho(gbar, self.somaarea) # mmho/cm2 - 4244.1 moh - 4.2441
nach = self.status["na"]
if nach == "jsrna":
soma().jsrna.gbar = gnabar
soma.ena = self.e_na
if debug:
print("octopus using jsrna, gbar: ", soma().jsrna.gbar)
elif nach == "nav11":
soma().nav11.gbar = gnabar
soma.ena = self.e_na
soma().nav11.vsna = 4.3
if debug:
print("octopus using inva11, gbar:", soma().nav11.gbar)
elif nach in ["na", "nacn"]:
soma().nacn.gbar = gnabar
soma.ena = self.e_na
if debug:
print("octopus cell using na/nacn, gbar: ", soma().na.gbar)
else:
raise ValueError(
"Sodium channel %s is not recognized for octopus cells", nach
)
class OctopusSpencer(Octopus, Cell):
"""
VCN octopus cell model (with dendrites).
Based on Spencer et al Front. Comput. Neurosci., 22 October 2012
https://doi.org/10.3389/fncom.2012.00083
"""
def __init__(
self,
morphology=None,
decorator=None,
nach="jsrna",
ttx=False,
species="guineapig",
modelType=None,
debug=False,
):
"""
initialize the octopus cell, using the parameters Spencer et al. 2012
Modifications to the cell can be made by calling methods below.
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 mechanism
by that name must exist.
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 (e.g., "II", "II-I", etc).
modelType is passed to the decorator, or to species_scaling to adjust point models.
debug: boolean (default: False)
debug is a boolean flag. When set, there will be multiple printouts of progress and parameters.
Returns
-------
Nothing
"""
super(OctopusSpencer, self).__init__()
if modelType == None:
modelType = "Spencer"
self.status = {
"soma": True,
"axon": False,
"dendrites": False,
"pumps": False,
"na": nach,
"species": species,
"modelType": modelType,
"ttx": ttx,
"name": "Octopus",
"morphology": morphology,
"decorator": decorator,
"temperature": None,
}
self.i_test_range = (-4.0, 6.0, 0.25)
self.spike_threshold = -50
self.vrange = [-75.0, -63.0] # set a default vrange for searching for rmp
if morphology is None:
"""
instantiate a basic soma-only ("point") model
"""
soma = h.Section(
name="Octopus_Soma_%x" % id(self)
) # one compartment of about 29000 um2
soma.nseg = 1
self.add_section(soma, "soma")
self.set_soma_size_from_Section(self.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.e_leak = -62.0 # from Spencer et al., 2012
self.e_h = -38.0 ## from Spencer et al., 2012
self.R_a = 100.0 # from Spencer et al., 2012
self.mechanisms = ["klt", "kht", "hcnobo", "leak", nach]
for mech in self.mechanisms:
self.soma.insert(mech)
self.soma.ek = -70.0 # self.e_k
self.soma.ena = 55.0 # self.e_na
self.soma().hcnobo.eh = self.e_h
self.soma().leak.erev = self.e_leak
self.soma.Ra = self.R_a
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.decorated.channelValidate(self, verify=True)
# print 'Mechanisms inserted: ', self.mechanisms
self.get_mechs(self.soma)
# self.cell_initialize(vrange=self.vrange)
if debug:
print("<< octopus: octopus cell model created >>")
# print 'Cell created: ', self.status
def channel_manager(self, modelType="Spencer"):
"""
This routine defines channel density maps and distance map patterns
for each type of compartment in the cell. The maps
are used by the ChannelDecorator class (specifically, it's private
\_biophys function) to decorate the cell membrane.
Parameters
----------
modelType : string (default: 'Spencer')
A string that defines the type of the model. Currently, 1 type is implemented:
Spencer : Spencer et al Front. Comput. Neurosci. 2012
Returns
-------
Nothing
Notes
-----
This routine defines the following variables for the class:
# conductances (gBar)
# a channelMap (dictonary of channel densities in defined anatomical compartments)
# a current injection range for IV's (when testing)
# a distance map, which defines how selected conductances in selected compartments
will change with distance. This includes both linear and exponential gradients,
the minimum conductance at the end of the gradient, and the space constant or
slope for the gradient.
"""
#
# Create a model based on the Spencer model
# Channel decoration and stick model from Figure 2
# densities from Tables 2 and 3
if modelType == "Spencer":
# print self.c_m
self.c_m = 0.9
# self.set_soma_size_from_Section(self.soma)
totcap = self.totcap
refarea = self.somaarea # totcap / self.c_m # see above for units
# self.print_soma_info()
self._valid_temperatures = (
34.0,
) # 34 for consistency with other mouse models, but
# Spencer data used "33". This affects very slightly
# the HCN channel conductance.
if self.status["temperature"] is None:
self.set_temperature(34.0)
self.gBar = Params(
nabar=0.0, # 0.0407, # S/cm2
nabar_ais=0.42441,
kltbar_ais=0.0,
khtbar_ais=0.0,
ihbar_ais=0.0,
kltbar_soma=0.0407,
khtbar_soma=0.0061,
ihbar_soma=0.0076,
kltbar_dend=0.0027,
khtbar_dend=0.0,
ihbar_dend=0.0006,
khtbar_hillock=0.0,
kltbar_hillock=0.0,
ihbar_hillock=0.0,
leakbar=0.0020,
)
self.channelMap = {
"soma": {
"jsrna": self.gBar.nabar,
"klt": self.gBar.kltbar_soma,
"kht": self.gBar.khtbar_soma,
"hcnobo": self.gBar.ihbar_soma,
"leak": self.gBar.leakbar,
},
"hillock": {
"jsrna": 0.0,
"klt": self.gBar.kltbar_hillock,
"kht": self.gBar.khtbar_hillock,
"hcnobo": self.gBar.ihbar_hillock,
"leak": self.gBar.leakbar,
},
# axon initial segment:
"unmyelinatedaxon": {
"jsrna": self.gBar.nabar_ais,
"klt": self.gBar.kltbar_ais,
"kht": self.gBar.khtbar_ais,
"hcnobo": self.gBar.ihbar_ais,
"leak": self.gBar.leakbar,
},
"primarydendrite": {
"jsrna": 0.0,
"klt": self.gBar.kltbar_dend,
"kht": self.gBar.khtbar_dend,
"hcnobo": self.gBar.ihbar_dend,
"leak": self.gBar.leakbar,
},
}
self.distMap = {
"primarydendrite": {
"klt": {"gradient": "flat", "gminf": 0.0, "lambda": 100.0},
"kht": {"gradient": "flat", "gminf": 0.0, "lambda": 100.0},
"hcnobo": {"gradient": "flat", "gminf": 0.0, "lambda": 100.0},
} # all flat with distance
}
# reversal potential map
self.channelErevMap = {
"soma": {
"jsrna": 55.0,
"klt": -70,
"kht": -70,
"hcnobo": -38,
"leak": -62.0,
},
"hillock": {
"jsrna": 55.0,
"klt": -70,
"kht": -70,
"hcnobo": -38,
"leak": -62.0,
},
"unmyelinatedaxon": {
"jsrna": 55.0,
"klt": -70,
"kht": -70,
"hcnobo": -38,
"leak": -62.0,
},
"primarydendrite": {
"jsrna": 55.0,
"klt": -70,
"kht": -70,
"hcnobo": -38,
"leak": -62.0,
},
}
else:
raise ValueError("model type %s is not implemented" % modelType)
self.check_temperature()
def species_scaling(self, species="mouse", modelType="Spencer", silent=True):
"""
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 guineapig
modelType: string (default: 'II-o')
definition of model type from RM03 models, currently limited to type II-o
silent : boolean (default: True)
run silently (True) or verbosely (False)
"""
soma = self.soma
if species == "mouse" and modelType == "Spencer":
print("Octopus: Mouse, Spencer point model - not a valid model")
self.set_soma_size_from_Cm(25.0)
self._valid_temperatures = (34.0,)
if self.status["temperature"] is None:
self.set_temperature(34.0)
self.print_soma_info()
# self.adjust_na_chans(soma)
# soma().kht.gbar = 0.0061 # nstomho(150.0, self.somaarea) # 6.1 mmho/cm2
# soma().klt.gbar = 0.0407 # nstomho(3196.0, self.somaarea) # 40.7 mmho/cm2
# soma().hcnobo.gbar = 0.0076 #nstomho(40.0, self.somaarea) # 7.6 mmho/cm2, cf. Bal and Oertel, Spencer et al. 25 u dia cell
# soma().leak.gbar = 0.0005 # nstomho(2.0, self.somaarea)
self.axonsf = 1.0
else:
raise ValueError(
'Species "%s" or species-type "%s" is not recognized for octopus cells'
% (species, type)
)
self.status["species"] = species
self.status["modelType"] = modelType
self.cell_initialize(showinfo=True)
if not silent:
print("set cell as: ", species)
print(" with Vm rest = %6.3f" % self.vm0)

482
cnmodel/cells/pyramidal.py Normal file
View File

@@ -0,0 +1,482 @@
from __future__ import print_function
import numpy as np
from neuron import h
from .cell import Cell
from .. import data
from ..util import Params
from ..util import nstomho
__all__ = ["Pyramidal", "PyramidalKanold"]
class Pyramidal(Cell):
type = "pyramidal"
@classmethod
def create(cls, model="POK", **kwds):
if model == "POK":
return PyramidalKanold(**kwds)
else:
raise ValueError("Pyramidal model %s is unknown", model)
def make_psd(self, terminal, psd_type, **kwds):
"""
Connect a presynaptic terminal to one post section at the specified location, with the fraction
of the "standard" conductance determined by gbar.
The default condition is to try to pass the default unit test (loc=0.5)
Parameters
----------
terminal : Presynaptic terminal (NEURON object)
psd_type : either simple or multisite PSD for bushy cell
kwds: dict of options. Two are currently handled:
postsize : expect a list consisting of [sectionno, location (float)]
AMPAScale : float to scale the ampa currents
"""
if (
"postsite" in kwds
): # use a defined location instead of the default (soma(0.5)
postsite = kwds["postsite"]
loc = postsite[1] # where on the section?
uname = (
"sections[%d]" % postsite[0]
) # make a name to look up the neuron section object
post_sec = self.hr.get_section(uname) # Tell us where to put the synapse.
else:
loc = 0.5
post_sec = self.soma
if psd_type == "simple":
if terminal.cell.type in [
"sgc",
"dstellate",
"tuberculoventral",
"cartwheel",
]:
weight = data.get(
"%s_synapse" % terminal.cell.type,
species=self.species,
post_type=self.type,
field="weight",
)
tau1 = data.get(
"%s_synapse" % terminal.cell.type,
species=self.species,
post_type=self.type,
field="tau1",
)
tau2 = data.get(
"%s_synapse" % terminal.cell.type,
species=self.species,
post_type=self.type,
field="tau2",
)
erev = data.get(
"%s_synapse" % terminal.cell.type,
species=self.species,
post_type=self.type,
field="erev",
)
return self.make_exp2_psd(
post_sec,
terminal,
weight=weight,
loc=loc,
tau1=tau1,
tau2=tau2,
erev=erev,
)
else:
raise TypeError(
"Cannot make simple PSD for %s => %s"
% (terminal.cell.type, self.type)
)
elif psd_type == "multisite":
if terminal.cell.type == "sgc":
# Max conductances for the glu mechanisms are calibrated by
# running `synapses/tests/test_psd.py`. The test should fail
# if these values are incorrect
self.AMPAR_gmax = (
data.get(
"sgc_synapse",
species=self.species,
post_type=self.type,
field="AMPAR_gmax",
)
* 1e3
)
self.NMDAR_gmax = (
data.get(
"sgc_synapse",
species=self.species,
post_type=self.type,
field="NMDAR_gmax",
)
* 1e3
)
self.Pr = data.get(
"sgc_synapse", species=self.species, post_type=self.type, field="Pr"
)
# adjust gmax to correct for initial Pr
self.AMPAR_gmax = self.AMPAR_gmax / self.Pr
self.NMDAR_gmax = self.NMDAR_gmax / self.Pr
if "AMPAScale" in kwds:
self.AMPA_gmax = (
self.AMPA_gmax * kwds["AMPAScale"]
) # allow scaling of AMPA conductances
if "NMDAScale" in kwds:
self.NMDA_gmax = self.NMDA_gmax * kwds["NMDAScale"]
return self.make_glu_psd(
post_sec, terminal, self.AMPAR_gmax, self.NMDAR_gmax, loc=loc
)
elif terminal.cell.type == "dstellate": # WBI input -Voigt, Nelken, Young
return self.make_gly_psd(post_sec, terminal, psdtype="glyfast", loc=loc)
elif (
terminal.cell.type == "tuberculoventral"
): # TV cells talk to each other-Kuo et al.
return self.make_gly_psd(post_sec, terminal, psdtype="glyfast", loc=loc)
else:
raise TypeError(
"Cannot make PSD for %s => %s" % (terminal.cell.type, self.type)
)
else:
raise ValueError("Unsupported psd type %s" % psd_type)
class PyramidalKanold(Pyramidal, Cell):
"""
DCN pyramidal cell
Kanold and Manis, 1999, 2001, 2005
"""
def __init__(
self,
morphology=None,
decorator=None,
nach=None,
ttx=False,
species="rat",
modelType=None,
debug=False,
):
"""
initialize a pyramidal cell, based on the Kanold-Manis (2001) pyramidal cell model.
Modifications to the cell can be made by calling methods below. These include
converting to a model with modified size and conductances (experimental).
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 is inserted into the first soma section, and the
rest of the structure is "bare".
nach : string (default: None)
nach selects the type of sodium channel that will be used in the model. A channel mechanim
by that name must exist. None implies the default channel, 'napyr'.
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 (overridden by decorator).
modelType: string (default: None)
modelType specifies the type of the model that will be used (e.g., "II", "II-I", etc).
modelType is passed to the decorator, or to species_scaling to adjust point models.
debug: boolean (default: False)
debug is a boolean flag. When set, there will be multiple printouts of progress and parameters.
Returns
-------
Nothing
"""
super(PyramidalKanold, self).__init__()
if modelType == None:
modelType = "POK"
if nach == None:
nach = "napyr"
self.status = {
"soma": True,
"axon": False,
"dendrites": False,
"pumps": False,
"na": nach,
"species": species,
"modelType": modelType,
"ttx": ttx,
"name": "Pyramidal",
"morphology": morphology,
"decorator": decorator,
"temperature": None,
}
self.i_test_range = {"pulse": (-0.3, 0.401, 0.02)}
self.vrange = [-75.0, -60.0]
if morphology is None:
"""
instantiate a basic soma-only ("point") model
"""
soma = h.Section(
name="Pyramidal_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 = [
"napyr",
"kdpyr",
"kif",
"kis",
"ihpyr",
"leak",
"kcnq",
"nap",
]
for mech in self.mechanisms:
try:
self.soma.insert(mech)
except ValueError:
print("WARNING: Mechanism %s not found" % mech)
self.soma().kif.kif_ivh = -89.6
self.species_scaling(
silent=True, species=species, modelType=modelType
) # set the default type I-c 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("<< PYR: POK Pyramidal Cell created >>")
def get_cellpars(self, dataset, species="guineapig", celltype="II"):
cellcap = data.get(
dataset, species=species, cell_type=celltype, field="soma_Cap"
)
chtype = data.get(
dataset, species=species, cell_type=celltype, field="soma_natype"
)
pars = Params(cap=cellcap, natype=chtype)
for g in [
"soma_napyr_gbar",
"soma_kdpyr_gbar",
"soma_kif_gbar",
"soma_kis_gbar",
"soma_kcnq_gbar",
"soma_nap_gbar",
"soma_ihpyr_gbar",
"soma_leak_gbar",
"soma_e_h",
"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, species="rat", modelType="I", silent=True):
"""
Adjust all of the conductances and the cell size according to the species requested.
Used ONLY for point models.
Parameters
----------
species : string (default: 'rat')
name of the species to use for scaling the conductances in the base point model
Must be 'rat'
modelType: string (default: 'I')
definition of model type from Kanold and Manis, 2001
choices are 'I' or 'POK' (canonical model) or
'II', a modified model with more physiological surface area and KCNQ channels
silent : boolean (default: True)
run silently (True) or verbosely (False)
"""
if modelType in ["I", "POK"]:
celltype = "pyramidal"
elif modelType in ["II"]:
celltype = "pyramidal-II"
else:
celltype = modelType
dataset = "POK_channels"
soma = self.soma
if species in ["rat", "mouse"] and modelType in [
"I",
"POK",
"II",
]: # canonical K&M2001 model cell
self._valid_temperatures = (34.0,)
if self.status["temperature"] is None:
self.set_temperature(34.0)
pars = self.get_cellpars(dataset, species=species, celltype=celltype)
self.set_soma_size_from_Cm(pars.cap)
self.status["na"] = pars.natype
soma().napyr.gbar = nstomho(pars.soma_napyr_gbar, self.somaarea)
soma().nap.gbar = nstomho(
pars.soma_nap_gbar, self.somaarea
) # does not exist in canonical model
soma().kdpyr.gbar = nstomho(pars.soma_kdpyr_gbar, self.somaarea)
soma().kcnq.gbar = nstomho(
pars.soma_kcnq_gbar, self.somaarea
) # does not exist in canonical model.
soma().kif.gbar = nstomho(pars.soma_kif_gbar, self.somaarea)
soma().kis.gbar = nstomho(pars.soma_kis_gbar, self.somaarea)
soma().ihpyr.gbar = nstomho(pars.soma_ihpyr_gbar, self.somaarea)
# soma().ihpyr_adj.q10 = 3.0 # no temp scaling to sta
soma().leak.gbar = nstomho(pars.soma_leak_gbar, self.somaarea)
soma().leak.erev = pars.soma_leak_erev
soma().ena = pars.soma_e_na
soma().ek = pars.soma_e_k
soma().ihpyr.eh = pars.soma_e_h
# elif species in 'rat' and modelType == 'II':
# """
# Modified canonical K&M2001 model cell
# In this model version, the specific membrane capacitance is modified
# so that the overall membrane time constant is consistent with experimental
# measures in slices. However, this is not a physiological value. Attempts
# to use the normal 1 uF/cm2 value were unsuccessful in establishing the expected
# ~12 msec time constant.
# This model also adds a KCNQ channel, as described by Li et al., 2012.
# """
# self.c_m = 6.0
# self.set_soma_size_from_Diam(30.0)
# # self.set_soma_size_from_Cm(80.0)
# # print 'diameter: %7.1f' % self.soma.diam
# self._valid_temperatures = (34.,)
# if self.status['temperature'] is None:
# self.set_temperature(34.)
# self.refarea = self.somaarea
# soma().napyr.gbar = nstomho(550, self.refarea)
# soma().nap.gbar = nstomho(60.0, self.refarea)
# soma().kcnq.gbar = nstomho(2, self.refarea) # pyramidal cells have kcnq: Li et al, 2011 (Thanos)
# soma().kdpyr.gbar = nstomho(180, self.refarea) # Normally 80.
# soma().kif.gbar = nstomho(150, self.refarea) # normally 150
# soma().kis.gbar = nstomho(40, self.refarea) # 40
# soma().ihpyr.gbar = nstomho(2.8, self.refarea)
# soma().leak.gbar = nstomho(0.5, self.refarea)
# soma().leak.erev = -62. # override default values in cell.py
# soma().ena = 50.0
# soma().ek = -81.5
# soma().ihpyr.eh = -43
# if not self.status['dendrites']:
# self.add_dendrites()
else:
raise ValueError(
"Species %s or species-modelType %s is not implemented for Pyramidal cells"
% (species, modelType)
)
self.status["species"] = species
self.status["modelType"] = modelType
# self.cell_initialize(showinfo=True)
self.check_temperature()
if not silent:
print("set cell as: ", species, modelType)
print(" with Vm rest = %f" % self.vm0)
print(self.status)
for m in self.mechanisms:
print("%s.gbar = %f" % (m, eval("soma().%s.gbar" % m)))
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
Overrides i_currents in cells.py because we have a different set of currents
to compute.
"""
for part in self.all_sections.keys():
for sec in self.all_sections[part]:
sec.v = V
h.celsius = self.status["temperature"]
h.finitialize()
self.ix = {}
if "napyr" in self.mechanisms:
self.ix["napyr"] = self.soma().napyr.gna * (V - self.soma().ena)
if "nap" in self.mechanisms:
self.ix["nap"] = self.soma().nap.gnap * (V - self.soma().ena)
if "kdpyr" in self.mechanisms:
self.ix["kdpyr"] = self.soma().kdpyr.gk * (V - self.soma().ek)
if "kif" in self.mechanisms:
self.ix["kif"] = self.soma().kif.gkif * (V - self.soma().ek)
if "kis" in self.mechanisms:
self.ix["kis"] = self.soma().kis.gkis * (V - self.soma().ek)
if "kcnq" in self.mechanisms:
self.ix["kcnq"] = self.soma().kcnq.gk * (V - self.soma().ek)
if "ihpyr" in self.mechanisms:
self.ix["ihpyr"] = self.soma().ihpyr.gh * (V - self.soma().ihpyr.eh)
if "ihpyr_adj" in self.mechanisms:
self.ix["ihpyr_adj"] = self.soma().ihpyr_adj.gh * (
V - self.soma().ihpyr_adj.eh
)
# leak
if "leak" in self.mechanisms:
self.ix["leak"] = self.soma().leak.gbar * (V - self.soma().leak.erev)
return np.sum([self.ix[i] for i in self.ix])
def add_dendrites(self):
"""
Add simple unbranched dendrite.
The dendrites have some kd, kif and ih current
"""
nDend = range(2) # these will be simple, unbranced, N=4 dendrites
dendrites = []
for i in nDend:
dendrites.append(h.Section(cell=self.soma))
for i in nDend:
dendrites[i].connect(self.soma)
dendrites[i].L = 250 # length of the dendrite (not tapered)
dendrites[i].diam = 1
dendrites[i].cm = self.c_m
# h('dendrites[i].diam(0:1) = 2:1') # dendrite diameter, with tapering
dendrites[i].nseg = 21 # # segments in dendrites
dendrites[i].Ra = 150 # ohm.cm
dendrites[i].insert("napyr")
dendrites[i]().napyr.gbar = 0.00
dendrites[i].insert("kdpyr")
dendrites[i]().kdpyr.gbar = 0.002 # a little Ht
dendrites[i].insert("kif")
dendrites[i]().kif.gbar = 0.0001 # a little Ht
dendrites[i].insert("leak") # leak
dendrites[i]().leak.gbar = 0.00001
dendrites[i].insert("ihpyr_adj") # some H current
# mechanism missing so the ihvcn mechanism need to be inserted
dendrites[i].insert('ihvcn')
dendrites[i]().ihvcn.gbar = 0.0 # 0.00002
dendrites[i]().ihvcn.eh = -43.0
self.maindend = dendrites
self.status["dendrites"] = True
self.add_section(self.maindend, "maindend")

467
cnmodel/cells/sgc.py Normal file
View File

@@ -0,0 +1,467 @@
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])

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,227 @@
import os, pickle, pprint
import numpy as np
import neuron
import cnmodel
import cnmodel.cells as cells
from cnmodel.util import UserTester, reset
from cnmodel.protocols import IVCurve
"""
Cell-type tests
"""
def test_bushy():
reset(raiseError=False)
cell = cells.Bushy.create(species="guineapig", modelType="II")
CellTester("bushy_guineapig-typeII", cell)
def test_bushy21():
reset(raiseError=False)
cell = cells.Bushy.create(species="guineapig", modelType="II-I")
CellTester("bushy_guineapig-typeII-I", cell)
def test_bushy_mouse():
reset(raiseError=False)
cell = cells.Bushy.create(species="mouse", modelType="II")
CellTester("bushy-mouse-typeII", cell)
def test_tstellate():
reset(raiseError=False)
cell = cells.TStellate.create(species="guineapig", modelType="I-c")
CellTester("tstellate_guineapig-typeI-c", cell)
def test_tstellate_mouse():
reset(raiseError=False)
cell = cells.TStellate.create(species="mouse", modelType="I-c")
CellTester("tstellate_mouse-typeI-c", cell)
def test_tstellatet():
reset(raiseError=False)
cell = cells.TStellate.create(species="guineapig", modelType="I-t")
CellTester("tstellate_guineapig-typeI-t", cell)
# not implemented yet
# def test_tstellatet_mouse():
# reset(raiseError=False)
# cell = cells.TStellate.create(species='mouse', modelType='I-t')
# CellTester('tstellate_mouse-typeI-t', cell)
def test_dstellate():
reset(raiseError=False)
cell = cells.DStellate.create(species="guineapig", modelType="I-II")
CellTester("dstellate_guineapig-typeI-II", cell)
def test_dstellate_mouse():
reset(raiseError=False)
cell = cells.DStellate.create(species="mouse", modelType="I-II")
CellTester("dstellate_mouse-typeI-II", cell)
def test_octopus():
reset(raiseError=False)
cell = cells.Octopus.create(species="guineapig", modelType="II-o")
CellTester("octopus_guineapig-typeII-o", cell)
def test_pyramidal():
reset(raiseError=False)
cell = cells.Pyramidal.create(species="rat", modelType="I")
CellTester("pyramidal_rat_I", cell)
def test_tuberculoventral():
reset(raiseError=False)
cell = cells.Tuberculoventral.create(species="mouse", modelType="TVmouse")
CellTester("tuberculoventral_mouse_I", cell)
def test_cartwheel():
reset(raiseError=False)
cell = cells.Cartwheel.create(species="mouse", modelType="I")
CellTester("cartwheel_rat_I", cell)
def test_sgc_basal_middle():
reset(raiseError=False)
cell = cells.SGC.create(species="mouse", modelType="bm")
CellTester("SGC_rat_bm", cell)
def test_sgc_apical():
reset(raiseError=False)
cell = cells.SGC.create(species="mouse", modelType="a")
CellTester("SGC_rat_a", cell)
#
# Supporting functions
#
class CellTester(UserTester):
data_dir = "cell_data"
def run_test(self, cell):
# run I/V test on cell
V0 = cell.find_i0(showinfo=True)
rmrintau = cell.compute_rmrintau(auto_initialize=False, vrange=None)
iv = IVCurve()
self.iv = iv
iv.run(cell.i_test_range, cell)
if self.audit:
iv.show(cell)
info = dict(
temp=iv.temp,
icmd=iv.current_cmd,
spikes=iv.spike_times(),
rmp=iv.rest_vm(),
rm_taum=iv.input_resistance_tau(),
vpeak=iv.peak_vm(),
vss=iv.steady_vm(),
rmrintau=rmrintau,
)
return info
def assert_test_info(self, *args, **kwds):
try:
super(CellTester, self).assert_test_info(*args, **kwds)
finally:
if hasattr(self, "iv") and hasattr(self.iv, "win"):
self.iv.win.hide()
# def result_file(key):
# """
# Return a file name to be used for storing / retrieving test results
# given *key*.
# """
# path = os.path.dirname(__file__)
# return os.path.join(path, 'cell_data', key + '.pk')
# def load_cell_info(key):
# """
# Load prior test results for *key*.
# If there are no prior results, return None.
# """
# fn = result_file(key)
# if os.path.isfile(fn):
# return pickle.load(open(fn, 'rb'))
# return None
# def save_cell_info(info, key):
# """
# Store test results for *key*.
# """
# fn = result_file(key)
# dirname = os.path.dirname(fn)
# if not os.path.isdir(dirname):
# os.mkdir(dirname)
# pickle.dump(info, open(fn, 'wb'))
# The following is superseeded by the built in unit tests.
# def CellTester(key):
# """
# Test *cell* and raise exception if the results do not match prior
# data.
# """
# audit = cnmodel.AUDIT_TESTS
## run I/V test on cell
# iv = IVCurve()
# iv.run(cell.i_test_range, cell)
# iv.show(cell)
# try:
# info = dict(
# icmd=iv.current_cmd,
# spikes=iv.spike_times(),
# rmp=iv.rest_vm(),
# rm=iv.input_resistance(),
# vpeak=iv.peak_vm(),
# vss=iv.steady_vm(),
# )
# expect = load_cell_info(key)
# if expect is not None:
## Check test structures are the same
# assert len(info) == len(expect)
# for k in info:
# assert k in expect
## Check data matches
# for k in info:
# if isinstance(info[k], list):
# assert len(info[k]) == len(expect[k])
# for i in range(len(info[k])):
# assert np.allclose(info[k][i], expect[k][i])
# else:
# assert np.allclose(info[k], expect[k])
# else:
# if not audit:
# raise Exception("No prior test results for cell type '%s'. "
# "Run test.py --audit store new test data." % key)
# print "\n=== New test results for %s: ===\n" % key
# pprint.pprint(info)
# print "Store new test results? [y/n]",
# yn = raw_input()
# if yn.lower().startswith('y'):
# save_cell_info(info, key)
# else:
# raise Exception("Rejected test results for '%s'" % key)
# finally:
# iv.win.hide()

1089
cnmodel/cells/tstellate.py Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,619 @@
from __future__ import print_function
from neuron import h
import numpy as np
# import neuron as nrn
from .cell import Cell
from .. import synapses
from ..util import nstomho
from ..util import Params
from .. import data
__all__ = ["Tuberculoventral"]
class Tuberculoventral(Cell):
type = "tuberculoventral"
@classmethod
def create(cls, model="TVmouse", **kwds):
if model in ["TVmouse", "I"]:
return Tuberculoventral(**kwds)
elif model == "dummy":
return DummyTuberculoventral(**kwds)
else:
raise ValueError("Tuberculoventral type %s is unknown", model)
def __init__(self):
Cell.__init__(self)
self.spike_source = (
None
) # used by DummyTuberculoventral to connect VecStim to terminal
def make_psd(self, terminal, psd_type, **kwds):
"""
Connect a presynaptic terminal to one post section at the specified location, with the fraction
of the "standard" conductance determined by gbar.
The default condition is to try to pass the default unit test (loc=0.5)
Parameters
----------
terminal : Presynaptic terminal (NEURON object)
psd_type : either simple or multisite PSD for bushy cell
kwds: dict of options. Two are currently handled:
postsize : expect a list consisting of [sectionno, location (float)]
AMPAScale : float to scale the ampa currents
"""
if (
"postsite" in kwds
): # use a defined location instead of the default (soma(0.5)
postsite = kwds["postsite"]
loc = postsite[1] # where on the section?
uname = (
"sections[%d]" % postsite[0]
) # make a name to look up the neuron section object
post_sec = self.hr.get_section(uname) # Tell us where to put the synapse.
else:
loc = 0.5
post_sec = self.soma
if psd_type == "simple":
if terminal.cell.type in ["sgc", "dstellate", "tuberculoventral"]:
weight = data.get(
"%s_synapse" % terminal.cell.type,
species=self.species,
post_type=self.type,
field="weight",
)
tau1 = data.get(
"%s_synapse" % terminal.cell.type,
species=self.species,
post_type=self.type,
field="tau1",
)
tau2 = data.get(
"%s_synapse" % terminal.cell.type,
species=self.species,
post_type=self.type,
field="tau2",
)
erev = data.get(
"%s_synapse" % terminal.cell.type,
species=self.species,
post_type=self.type,
field="erev",
)
return self.make_exp2_psd(
post_sec,
terminal,
weight=weight,
loc=loc,
tau1=tau1,
tau2=tau2,
erev=erev,
)
else:
raise TypeError(
"Cannot make simple PSD for %s => %s"
% (terminal.cell.type, self.type)
)
elif psd_type == "multisite":
if terminal.cell.type == "sgc":
# Max conductances for the glu mechanisms are calibrated by
# running `synapses/tests/test_psd.py`. The test should fail
# if these values are incorrect
self.AMPAR_gmax = (
data.get(
"sgc_synapse",
species=self.species,
post_type=self.type,
field="AMPAR_gmax",
)
* 1e3
)
self.NMDAR_gmax = (
data.get(
"sgc_synapse",
species=self.species,
post_type=self.type,
field="NMDAR_gmax",
)
* 1e3
)
self.Pr = data.get(
"sgc_synapse", species=self.species, post_type=self.type, field="Pr"
)
# adjust gmax to correct for initial Pr
self.AMPAR_gmax = self.AMPAR_gmax / self.Pr
self.NMDAR_gmax = self.NMDAR_gmax / self.Pr
if "AMPAScale" in kwds:
self.AMPA_gmax = (
self.AMPA_gmax * kwds["AMPAScale"]
) # allow scaling of AMPA conductances
if "NMDAScale" in kwds:
self.NMDA_gmax = self.NMDA_gmax * kwds["NMDAScale"]
return self.make_glu_psd(
post_sec, terminal, self.AMPAR_gmax, self.NMDAR_gmax, loc=loc
)
elif terminal.cell.type == "dstellate": # WBI input -Voigt, Nelken, Young
return self.make_gly_psd(post_sec, terminal, psdtype="glyfast", loc=loc)
elif (
terminal.cell.type == "tuberculoventral"
): # TV cells talk to each other-Kuo et al.
return self.make_gly_psd(post_sec, terminal, psdtype="glyfast", loc=loc)
else:
raise TypeError(
"Cannot make PSD for %s => %s" % (terminal.cell.type, self.type)
)
else:
raise ValueError("Unsupported psd type %s" % psd_type)
def make_terminal(self, post_cell, term_type, **kwds):
pre_sec = self.soma
if term_type == "simple":
return synapses.SimpleTerminal(
pre_sec, post_cell, spike_source=self.spike_source, **kwds
)
elif term_type == "multisite":
if post_cell.type in [
"dstellate",
"tuberculoventral",
"pyramidal",
"bushy",
"tstellate",
]:
nzones = data.get(
"tuberculoventral_synapse",
species=self.species,
post_type=post_cell.type,
field="n_rsites",
)
delay = data.get(
"tuberculoventral_synapse",
species=self.species,
post_type=post_cell.type,
field="delay",
)
else:
raise NotImplementedError(
"No knowledge as to how to connect tuberculoventral cell to cell type %s"
% type(post_cell)
)
pre_sec = self.soma
return synapses.StochasticTerminal(
pre_sec,
post_cell,
nzones=nzones,
spike_source=self.spike_source,
delay=delay,
**kwds
)
else:
raise ValueError("Unsupported terminal type %s" % term_type)
class Tuberculoventral(Tuberculoventral):
"""
Tuberculoventral Neuron (DCN) base model
Adapted from T-stellate model, using target parameters from Kuo et al. J. Neurophys. 2012
"""
def __init__(
self,
morphology=None,
decorator=None,
nach=None,
ttx=False,
species="mouse",
modelType=None,
debug=False,
):
"""
Initialize a DCN Tuberculoventral cell, using the default parameters for guinea pig from
R&M2003, as a type I cell.
Modifications to the cell can be made by calling methods below. These include:
Converting to a type IA model (add transient K current) (species: guineapig-TypeIA).
Changing "species" to mouse or cat (scales 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 mechanims
by that name must exist.
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 (e.g., "II", "II-I", etc).
modelType is passed to the decorator, or to species_scaling to adjust point models.
debug: boolean (default: False)
debug is a boolean flag. When set, there will be multiple printouts of progress and parameters.
Returns
-------
Nothing
"""
super(Tuberculoventral, self).__init__()
if modelType == None:
modelType = "TVmouse"
if nach == None:
nach = "nacncoop"
self.debug = debug
self.status = {
"soma": True,
"axon": False,
"dendrites": False,
"pumps": False,
"na": nach,
"species": species,
"modelType": modelType,
"ttx": ttx,
"name": "Tuberculoventral",
"morphology": morphology,
"decorator": decorator,
"temperature": None,
}
self.i_test_range = {"pulse": [(-0.35, 1.0, 0.05), (-0.04, 0.01, 0.01)]}
self.vrange = [-80.0, -60.0] # set a default vrange for searching for rmp
if morphology is None:
"""
instantiate a basic soma-only ("point") model
"""
if self.debug:
print("<< Tuberculoventral model: Creating point cell >>")
soma = h.Section(
name="Tuberculoventral_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
"""
if self.debug:
print("<< Tuberculoventral model: Creating structured cell >>")
self.set_morphology(morphology_file=morphology)
# decorate the morphology with ion channels
if decorator is None: # basic model, only on the soma
self.mechanisms = ["kht", "ka", "ihvcn", "leak", nach]
for mech in self.mechanisms:
self.soma.insert(mech)
self.species_scaling(
silent=True, species=species, modelType=modelType
) # adjust the default 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 self.debug:
print("<< Tuberculoventral cell model created >>")
def get_cellpars(self, dataset, species="mouse", celltype="TVmouse"):
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, soma_na_type=chtype)
for g in [
"soma_nacncoop_gbar",
"soma_kht_gbar",
"soma_ka_gbar",
"soma_ihvcn_gbar",
"soma_ihvcn_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, species="guineapig", modelType="TVmouse", silent=True):
"""
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, cat, guineapig
modelType: string (default: 'I-c')
definition of model type from RM03 models, type I-c or type I-t
silent : boolean (default: True)
run silently (True) or verbosely (False)
"""
soma = self.soma
if self.debug:
print("modelType: ", modelType)
if modelType in ["TVmouse", "I"]:
celltype = "TVmouse" # modelType
modelType = "TVmouse"
else:
raise ValueError(
"Tuberuloventral: Model type %s not recognized" % modelType
)
if species == "mouse" and modelType in ["TVmouse", "I"]:
"""#From Kuo 150 Mohm, 10 msec tau
Firing at 600 pA about 400 Hz
These values from brute_force runs, getting 380 Hz at 600 pA at 35C
Input resistance and vm is ok, time constnat is short
*** Rin: 168 tau: 7.8 v: -68.4
Attempts to get longer time constant - cannot keep rate up.
"""
# Adapted from TStellate model type I-c'
self.vrange = [-80.0, -58.0]
self._valid_temperatures = (34.0,)
if self.status["temperature"] is None:
self.set_temperature(34.0)
pars = self.get_cellpars("TV_channels", species="mouse", celltype=modelType)
self.set_soma_size_from_Cm(pars.soma_cap)
self.status["na"] = pars.soma_na_type
self.adjust_na_chans(soma, gbar=pars.soma_nacncoop_gbar, debug=self.debug)
soma().kht.gbar = nstomho(pars.soma_kht_gbar, self.somaarea)
soma().ka.gbar = nstomho(pars.soma_ka_gbar, self.somaarea)
soma().ihvcn.gbar = nstomho(pars.soma_ihvcn_gbar, self.somaarea)
soma().ihvcn.eh = pars.soma_ihvcn_eh
soma().leak.gbar = nstomho(pars.soma_leak_gbar, self.somaarea)
soma().leak.erev = pars.soma_leak_erev
self.e_leak = pars.soma_leak_erev
self.soma.ek = self.e_k = pars.soma_e_k
self.soma.ena = self.e_na = pars.soma_e_na
self.axonsf = 0.5
else:
raise ValueError(
"Species %s or species-type %s is not recognized for Tuberculoventralcells"
% (species, type)
)
self.status["species"] = species
self.status["modelType"] = modelType
self.check_temperature()
def channel_manager(self, modelType="TVmouse"):
"""
This routine defines channel density maps and distance map patterns
for each type of compartment in the cell. The maps
are used by the ChannelDecorator class (specifically, it's private
_biophys function) to decorate the cell membrane.
Parameters
----------
modelType : string (default: 'RM03')
A string that defines the type of the model. Currently, 3 types are implemented:
RM03: Rothman and Manis, 2003 somatic densities for guinea pig
XM13: Xie and Manis, 2013, somatic densities for mouse
XM13PasDend: XM13, but with only passive dendrites, no channels.
Returns
-------
Nothing
Notes
-----
This routine defines the following variables for the class:
- conductances (gBar)
- a channelMap (dictonary of channel densities in defined anatomical compartments)
- a current injection range for IV's (when testing)
- a distance map, which defines how selected conductances in selected compartments
will change with distance. This includes both linear and exponential gradients,
the minimum conductance at the end of the gradient, and the space constant or
slope for the gradient.
"""
if modelType == "TVmouse":
print("decorate as tvmouse")
# totcap = 95.0E-12 # Tuberculoventral cell (type I), based on stellate, adjusted for Kuo et al. TV firing
self.set_soma_size_from_Section(self.soma)
totcap = self.totcap
refarea = self.somaarea # totcap / self.c_m # see above for units
self.gBar = Params(
nabar=1520.0e-9 / refarea,
khtbar=160.0e-9 / refarea,
kltbar=0.0e-9 / refarea,
kabar=65.0 / refarea,
ihbar=1.25e-9 / refarea,
leakbar=5.5e-9 / refarea,
)
self.channelMap = {
"axon": {
"nacn": 0.0,
"klt": 0.0,
"kht": self.gBar.khtbar,
"ihvcn": 0.0,
"leak": self.gBar.leakbar / 4.0,
},
"hillock": {
"nacn": self.gBar.nabar,
"klt": 0.0,
"kht": self.gBar.khtbar,
"ihvcn": 0.0,
"leak": self.gBar.leakbar,
},
"initseg": {
"nacn": self.gBar.nabar,
"klt": 0.0,
"kht": self.gBar.khtbar,
"ihvcn": self.gBar.ihbar / 2.0,
"leak": self.gBar.leakbar,
},
"soma": {
"nacn": self.gBar.nabar,
"klt": self.gBar.kltbar,
"kht": self.gBar.khtbar,
"ihvcn": self.gBar.ihbar,
"leak": self.gBar.leakbar,
},
"dend": {
"nacn": self.gBar.nabar / 2.0,
"klt": 0.0,
"kht": self.gBar.khtbar * 0.5,
"ihvcn": self.gBar.ihbar / 3.0,
"leak": self.gBar.leakbar * 0.5,
},
"apic": {
"nacn": 0.0,
"klt": 0.0,
"kht": self.gBar.khtbar * 0.2,
"ihvcn": self.gBar.ihbar / 4.0,
"leak": self.gBar.leakbar * 0.2,
},
}
self.irange = np.linspace(-0.3, 0.6, 10)
self.distMap = {
"dend": {
"klt": {"gradient": "linear", "gminf": 0.0, "lambda": 100.0},
"kht": {"gradient": "linear", "gminf": 0.0, "lambda": 100.0},
}, # linear with distance, gminf (factor) is multiplied by gbar
"apic": {
"klt": {"gradient": "linear", "gminf": 0.0, "lambda": 100.0},
"kht": {"gradient": "linear", "gminf": 0.0, "lambda": 100.0},
}, # gradients are: flat, linear, exponential
}
else:
raise ValueError("model type %s is not implemented" % modelType)
def adjust_na_chans(self, soma, gbar=1000.0, debug=False):
"""
Adjust the sodium channel conductance, depending on the type of conductance
Parameters
----------
soma : NEURON section object (required)
This identifies the soma object whose sodium channel complement will have it's
conductances adjusted depending on the sodium channel type
gbar : float (default: 1000.)
The "maximal" conductance to be set in the model.
debug : boolean (default: False)
A flag the prints out messages to confirm the operations applied.
Returns
-------
Nothing
"""
if self.status["ttx"]:
gnabar = 0.0
else:
gnabar = nstomho(gbar, self.somaarea)
nach = self.status["na"]
if nach == "nacncoop":
soma().nacncoop.gbar = gnabar
soma().nacncoop.KJ = 2000.0
soma().nacncoop.p = 0.25
soma.ena = self.e_na
if debug:
print("nacncoop gbar: ", soma().nacncoop.gbar)
elif 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("Tuberculoventral using inva11")
print("nav11 gbar: ", soma().nav11.gbar)
elif nach == "na":
soma().na.gbar = gnabar
soma.ena = self.e_na
if debug:
print("na gbar: ", soma().na.gbar)
elif nach == "nacn":
soma().nacn.gbar = gnabar
soma.ena = self.e_na
if debug:
print("nacn gbar: ", soma().nacn.gbar)
else:
raise ValueError(
"Tuberculoventral setting Na channels: channel %s not known" % nach
)
class DummyTuberculoventral(Tuberculoventral):
""" Tuberculoventral cell class with no cell body; this cell only replays a predetermined
spike train. Useful for testing, or replacing spike trains to determine
the importance of spike structures within a network.
"""
def __init__(self, cf=None, species="mouse"):
"""
Parameters
----------
cf : float (default: None)
Required: the characteristic frequency for the TV cell
Really just for reference.
"""
Tuberculoventral.__init__(self)
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": species,
"modelType": "Dummy",
"modelName": "DummyTuberculoventral",
"ttx": None,
"name": "DummyTuberculoventral",
"morphology": None,
"decorator": None,
"temperature": None,
}
print("<< Tuberculoventral: Dummy Tuberculoventral Cell created >>")
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)