You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
219 lines
6.2 KiB
219 lines
6.2 KiB
2 years ago
|
from __future__ import print_function
|
||
|
|
||
|
"""
|
||
|
Wrapper classes to make working with NEURON easier.
|
||
|
|
||
|
Author: Andrew P. Davison, UNIC, CNRS
|
||
|
"""
|
||
|
|
||
|
__version__ = "0.3.0"
|
||
|
|
||
|
from neuron import nrn, h, hclass
|
||
|
|
||
|
h.load_file("stdrun.hoc")
|
||
|
|
||
|
PROXIMAL = 0
|
||
|
DISTAL = 1
|
||
|
|
||
|
|
||
|
class Mechanism(object):
|
||
|
"""
|
||
|
Examples:
|
||
|
>>> leak = Mechanism('pas', {'e': -65, 'g': 0.0002})
|
||
|
>>> hh = Mechanism('hh')
|
||
|
added set_parameters to allow post-instantiation parameter modification
|
||
|
"""
|
||
|
|
||
|
def __init__(self, name, **parameters):
|
||
|
self.name = name
|
||
|
self.parameters = parameters
|
||
|
|
||
|
def set_parameters(self, parameters):
|
||
|
self.parameters = parameters
|
||
|
|
||
|
def insert_into(self, section):
|
||
|
section.insert(self.name)
|
||
|
for name, value in self.parameters.items():
|
||
|
for segment in section:
|
||
|
mech = getattr(segment, self.name)
|
||
|
setattr(mech, name, value)
|
||
|
|
||
|
|
||
|
class Section(nrn.Section):
|
||
|
"""
|
||
|
Examples:
|
||
|
>>> soma = Section(L=30, diam=30, mechanisms=[hh, leak])
|
||
|
>>> apical = Section(L=600, diam=2, nseg=5, mechanisms=[leak],
|
||
|
... parent=soma, connection_point=DISTAL)
|
||
|
"""
|
||
|
|
||
|
def __init__(
|
||
|
self,
|
||
|
L,
|
||
|
diam,
|
||
|
nseg=1,
|
||
|
Ra=100,
|
||
|
cm=1,
|
||
|
mechanisms=[],
|
||
|
parent=None,
|
||
|
connection_point=DISTAL,
|
||
|
):
|
||
|
nrn.Section.__init__(self)
|
||
|
# set geometry
|
||
|
self.L = L
|
||
|
self.diam = diam
|
||
|
self.nseg = nseg
|
||
|
# set cable properties
|
||
|
self.Ra = Ra
|
||
|
self.cm = cm
|
||
|
# connect to parent section
|
||
|
if parent:
|
||
|
self.connect(parent, connection_point, PROXIMAL)
|
||
|
# add ion channels
|
||
|
for mechanism in mechanisms:
|
||
|
mechanism.insert_into(self)
|
||
|
|
||
|
def add_synapses(self, label, type, locations=[0.5], **parameters):
|
||
|
if hasattr(self, label):
|
||
|
raise Exception("Can't overwrite synapse labels (to keep things simple)")
|
||
|
synapse_group = []
|
||
|
for location in locations:
|
||
|
synapse = getattr(h, type)(location, sec=self)
|
||
|
for name, value in parameters.items():
|
||
|
setattr(synapse, name, value)
|
||
|
synapse_group.append(synapse)
|
||
|
if len(synapse_group) == 1:
|
||
|
synapse_group = synapse_group[0]
|
||
|
setattr(self, label, synapse_group)
|
||
|
|
||
|
add_synapse = add_synapses # for backwards compatibility
|
||
|
|
||
|
def plot(self, variable, location=0.5, tmin=0, tmax=5, xmin=-80, xmax=40):
|
||
|
import neuron.gui
|
||
|
|
||
|
self.graph = h.Graph()
|
||
|
h.graphList[0].append(self.graph)
|
||
|
self.graph.size(tmin, tmax, xmin, xmax)
|
||
|
self.graph.addvar("%s(%g)" % (variable, location), sec=self)
|
||
|
|
||
|
def record_spikes(self, threshold=-30):
|
||
|
self.spiketimes = h.Vector()
|
||
|
self.spikecount = h.APCount(0.5, sec=self)
|
||
|
self.spikecount.thresh = threshold
|
||
|
self.spikecount.record(self.spiketimes)
|
||
|
|
||
|
|
||
|
def alias(attribute_path):
|
||
|
"""
|
||
|
Returns a new property, mapping an attribute nested in an object hierarchy
|
||
|
to a simpler name
|
||
|
|
||
|
For example, suppose that an object of class A has an attribute b which
|
||
|
itself has an attribute c which itself has an attribute d. Then placing
|
||
|
e = alias('b.c.d')
|
||
|
in the class definition of A makes A.e an alias for A.b.c.d
|
||
|
"""
|
||
|
|
||
|
parts = attribute_path.split(".")
|
||
|
attr_name = parts[-1]
|
||
|
attr_path = parts[:-1]
|
||
|
|
||
|
def set(self, value):
|
||
|
obj = reduce(getattr, [self] + attr_path)
|
||
|
setattr(obj, attr_name, value)
|
||
|
|
||
|
def get(self):
|
||
|
obj = reduce(getattr, [self] + attr_path)
|
||
|
return getattr(obj, attr_name)
|
||
|
|
||
|
return property(fset=set, fget=get)
|
||
|
|
||
|
|
||
|
def uniform_property(section_list, attribute_path):
|
||
|
"""
|
||
|
Define a property that will have a uniform value across a list of sections.
|
||
|
|
||
|
For example, suppose we define a neuron model as a class A, which contains
|
||
|
three compartments: soma, dendrite and axon. Then placing
|
||
|
|
||
|
gnabar = uniform_property(["soma", "axon"], "hh.gnabar")
|
||
|
|
||
|
in the class definition of A means that setting a.gnabar (where a is an
|
||
|
instance of A) will set the value of hh.gnabar in both the soma and axon, i.e.
|
||
|
|
||
|
a.gnabar = 0.01
|
||
|
|
||
|
is equivalent to:
|
||
|
|
||
|
for sec in [a.soma, a.axon]:
|
||
|
for seg in sec:
|
||
|
seg.hh.gnabar = 0.01
|
||
|
|
||
|
"""
|
||
|
parts = attribute_path.split(".")
|
||
|
attr_name = parts[-1]
|
||
|
attr_path = parts[:-1]
|
||
|
|
||
|
def set(self, value):
|
||
|
for sec_name in section_list:
|
||
|
sec = getattr(self, sec_name)
|
||
|
for seg in sec:
|
||
|
obj = reduce(getattr, [seg] + attr_path)
|
||
|
setattr(obj, attr_name, value)
|
||
|
|
||
|
def get(self):
|
||
|
sec = getattr(self, section_list[0])
|
||
|
obj = reduce(getattr, [sec(0.5)] + attr_path)
|
||
|
return getattr(obj, attr_name)
|
||
|
|
||
|
return property(fset=set, fget=get)
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
|
||
|
class SimpleNeuron(object):
|
||
|
def __init__(self):
|
||
|
# define ion channel parameters
|
||
|
leak = Mechanism("pas", e=-65, g=0.0002)
|
||
|
hh = Mechanism("hh")
|
||
|
# create cable sections
|
||
|
self.soma = Section(L=30, diam=30, mechanisms=[hh])
|
||
|
self.apical = Section(
|
||
|
L=600,
|
||
|
diam=2,
|
||
|
nseg=5,
|
||
|
mechanisms=[leak],
|
||
|
parent=self.soma,
|
||
|
connection_point=DISTAL,
|
||
|
)
|
||
|
self.basilar = Section(
|
||
|
L=600,
|
||
|
diam=2,
|
||
|
nseg=5,
|
||
|
mechanisms=[leak],
|
||
|
parent=self.soma,
|
||
|
connection_point=0.5,
|
||
|
)
|
||
|
self.axon = Section(
|
||
|
L=1000, diam=1, nseg=37, mechanisms=[hh], connection_point=0
|
||
|
)
|
||
|
# synaptic input
|
||
|
self.soma.add_synapses("syn", "AlphaSynapse", onset=0.5, gmax=0.05, e=0)
|
||
|
|
||
|
gnabar = uniform_property(["soma", "axon"], "hh.gnabar")
|
||
|
gkbar = uniform_property(["soma", "axon"], "hh.gkbar")
|
||
|
|
||
|
neuron = SimpleNeuron()
|
||
|
neuron.soma.plot("v")
|
||
|
neuron.apical.plot("v")
|
||
|
|
||
|
print("gNa_bar: ", neuron.gnabar)
|
||
|
neuron.gnabar = 0.15
|
||
|
assert neuron.soma(0.5).hh.gnabar == 0.15
|
||
|
|
||
|
h.dt = 0.025
|
||
|
v_init = -65
|
||
|
tstop = 5
|
||
|
h.finitialize(v_init)
|
||
|
h.run()
|