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.
318 lines
10 KiB
318 lines
10 KiB
2 years ago
|
"""
|
||
|
test_mechanisms.py
|
||
|
|
||
|
This program displays the results of inserting NEURON mechaanisms from .mod files
|
||
|
into a point cell to voltage steps in voltage clamp.
|
||
|
This code is primarily for visual verification of model function.
|
||
|
|
||
|
Usage: python test_mechanisms.py <mechname>
|
||
|
|
||
|
Available mechanisms::
|
||
|
|
||
|
CaPCalyx bkpkj hcno hcnobo hpkj
|
||
|
ihpyr ihsgcApical ihsgcBasalMiddle ihvcn jsrna
|
||
|
ka kcnq kdpyr kht kif
|
||
|
kis klt kpkj kpkj2 kpkjslow
|
||
|
kpksk leak lkpkj na naRsg
|
||
|
nacn nacncoop nap napyr nav11
|
||
|
|
||
|
Note: only modfiles that implement voltage-dependent ion channel models make sense to run
|
||
|
with this routine. the list "nottestablemechs" in the file defines mechanisms provided
|
||
|
with cnmodel that cannot be run with this program.
|
||
|
|
||
|
"""
|
||
|
import sys
|
||
|
from neuron import h
|
||
|
from neuron import nrn
|
||
|
|
||
|
import gc
|
||
|
import numpy as np
|
||
|
|
||
|
# import scipy as sp
|
||
|
import cnmodel.util
|
||
|
import pyqtgraph as pg
|
||
|
import pyqtgraph.exporters
|
||
|
from pyqtgraph.Qt import QtCore, QtGui
|
||
|
import cnmodel.util.pynrnutilities as Util
|
||
|
|
||
|
nottestablemechs = [
|
||
|
"cadyn",
|
||
|
"ca_ion",
|
||
|
"cadiff",
|
||
|
"cadifpmp",
|
||
|
"Mechanism",
|
||
|
"capmp",
|
||
|
"capump",
|
||
|
"cl_ion",
|
||
|
"extracellular",
|
||
|
"fastpas",
|
||
|
"k_ion",
|
||
|
"KIR",
|
||
|
"hh",
|
||
|
"na_ion",
|
||
|
"narsg",
|
||
|
"pas",
|
||
|
"cap",
|
||
|
] # cap uses "pcabar"
|
||
|
|
||
|
|
||
|
class ChannelKinetics:
|
||
|
def __init__(self, args, export=False):
|
||
|
modfile = []
|
||
|
if isinstance(args, list):
|
||
|
for arg in args:
|
||
|
modfile.append(arg) # must be string, not list...
|
||
|
else:
|
||
|
modfile.append(args) # 'CaPCalyx'
|
||
|
print("modfile: ", modfile)
|
||
|
colors = ["b", "r", "g", "y", "c", "m", "w"]
|
||
|
if len(modfile) > len(colors):
|
||
|
print("Too many modfiles... keep it simple!")
|
||
|
exit()
|
||
|
# if isinstance(args, list) and len(args) > 1:
|
||
|
# modfile2 = args[1]
|
||
|
doKinetics = False
|
||
|
self.app = pg.mkQApp()
|
||
|
self.win = pg.GraphicsWindow()
|
||
|
self.win.setWindowTitle("VC Plots")
|
||
|
self.win.resize(600, 800)
|
||
|
# cw = QtGui.QWidget()
|
||
|
# self.win.setCentralWidget(cw)
|
||
|
# self.gridLayout = QtGui.QGridLayout()
|
||
|
# cw.setLayout(self.gridLayout)
|
||
|
# self.gridLayout.setContentsMargins(9, 9, 4, 4)
|
||
|
# self.gridLayout.setSpacing(1)
|
||
|
self.p1 = self.win.addPlot(title="I (VC)")
|
||
|
# self.gridLayout.addWidget(self.p1, 0, 0, 1, 1)
|
||
|
self.p2 = self.win.addPlot(title="I_ss, I_max")
|
||
|
# self.gridLayout.addWidget(self.p2, 0, 1, 1, 1)
|
||
|
self.win.nextRow()
|
||
|
self.p3 = self.win.addPlot(title="V command")
|
||
|
# self.gridLayout.addWidget(self.p3, 1, 0, 1, 1)
|
||
|
self.p5 = self.win.addPlot(title="I_min")
|
||
|
# self.gridLayout.addWidget(self.p5, 1, 1, 1, 1)
|
||
|
self.win.show()
|
||
|
QtGui.QApplication.processEvents()
|
||
|
#
|
||
|
# self.tdur is a table of durations for the pulse and post-pulse for each channel type (best to highlight features
|
||
|
# on appropriate time scales)
|
||
|
#
|
||
|
self.tdur = {
|
||
|
"CaPCalyx": [20.0, 10.0],
|
||
|
"nav11": [10.0, 5.0],
|
||
|
"jsrna": [10.0, 5.0],
|
||
|
"ichanWT2005": [10.0, 5.0],
|
||
|
"nacn": [10.0, 5.0],
|
||
|
"nacncoop": [10.0, 5.0],
|
||
|
"nabu": [10.0, 5.0],
|
||
|
"kht": [200.0, 20.0],
|
||
|
"klt": [200.0, 20.0],
|
||
|
"ka": [25.0, 5.0],
|
||
|
"hcno": [1000.0, 200.0],
|
||
|
"ih": [1000.0, 200.0],
|
||
|
"ihvcn": [1000.0, 200.0],
|
||
|
"hcnobo": [1000.0, 200.0],
|
||
|
"ihsgcBasalMiddle": [1000.0, 200.0],
|
||
|
"ihsgcApical": [1000.0, 200.0],
|
||
|
"kif": [100.0, 100.0],
|
||
|
"kis": [100.0, 10.0],
|
||
|
"napyr": [10, 5.0],
|
||
|
"ihpyr": [1000.0, 200.0],
|
||
|
"kdpyr": [200.0, 20.0],
|
||
|
"kcnq": [200, 20],
|
||
|
"nap": [200.0, 100.0],
|
||
|
}
|
||
|
for i, mfile in enumerate(modfile):
|
||
|
self.run(modfile=mfile, color=colors[i], export=export)
|
||
|
s = ""
|
||
|
# self.win.setWindowTitle('VC Plots: ' + [s+sn+'; ' for sn in modfile])
|
||
|
gc.collect()
|
||
|
|
||
|
if doKinetics:
|
||
|
self.win2 = pg.GraphicsWindow(title="KineticPlots")
|
||
|
self.win2.resize(800, 600)
|
||
|
self.kp1 = self.win.addPlot(title="htau")
|
||
|
self.computeKinetics("nav11")
|
||
|
|
||
|
# self.win.show()
|
||
|
|
||
|
def run(self, modfile="CaPCalyx", color="r", export=False):
|
||
|
if isinstance(modfile, list):
|
||
|
modfile = modfile[0]
|
||
|
|
||
|
if modfile in self.tdur:
|
||
|
tstep = self.tdur[modfile]
|
||
|
else:
|
||
|
tstep = [200.0, 50.0]
|
||
|
tdelay = 5.0
|
||
|
Channel = cnmodel.util.Mechanism(modfile)
|
||
|
leak = cnmodel.util.Mechanism("leak")
|
||
|
Channel.set_parameters({"gbar": 1})
|
||
|
leak.set_parameters({"gbar": 1e-12})
|
||
|
# if modfile == 'nacncoop':
|
||
|
# self.soma().nacncoop.p = 0.
|
||
|
# self.soma().nacncoop.KJ = 0.
|
||
|
# # Channel.set_parameters({'p': 0., 'KJ': 000.})
|
||
|
|
||
|
self.soma = cnmodel.util.Section(L=10, diam=10, mechanisms=[Channel, leak])
|
||
|
if modfile == "bkpjk":
|
||
|
ca_init = 100e-6
|
||
|
self.soma().cai = ca_init
|
||
|
else:
|
||
|
ca_init = 70e-6
|
||
|
if modfile == "nacncoop":
|
||
|
self.soma().nacncoop.p = 0.1
|
||
|
self.soma().nacncoop.KJ = 1000.0
|
||
|
# Channel.set_parameters({'p': 0., 'KJ': 000.})
|
||
|
h.celsius = 37.0 # set the temperature.
|
||
|
self.vec = {}
|
||
|
for var in ["time", "V", "IChan", "Vcmd"]:
|
||
|
self.vec[var] = h.Vector()
|
||
|
|
||
|
h.dt = 0.025
|
||
|
v_init = -65.0
|
||
|
|
||
|
clampV = v_init
|
||
|
self.vcPost = h.SEClamp(0.5, sec=self.soma)
|
||
|
self.vcPost.dur1 = tdelay
|
||
|
self.vcPost.amp1 = clampV
|
||
|
self.vcPost.dur2 = tstep[0]
|
||
|
self.vcPost.amp2 = clampV - 0.0 # just a tiny step to keep the system honest
|
||
|
self.vcPost.dur3 = tstep[1]
|
||
|
self.vcPost.amp3 = clampV
|
||
|
self.vcPost.rs = 1e-9
|
||
|
print("soma: ", self.soma, end=" ")
|
||
|
# print(dir(self.vcPost))
|
||
|
# print(' vcpost sec: ', self.vcPost.Section())
|
||
|
|
||
|
if modfile[0:2] == "ih":
|
||
|
stimamp = np.linspace(-140, -40, num=21, endpoint=True)
|
||
|
else:
|
||
|
stimamp = np.linspace(-100, 60, num=35, endpoint=True)
|
||
|
self.ivss = np.zeros((2, stimamp.shape[0]))
|
||
|
self.ivmin = np.zeros((2, stimamp.shape[0]))
|
||
|
self.ivmax = np.zeros((2, stimamp.shape[0]))
|
||
|
print(
|
||
|
(
|
||
|
"I range = %6.1f-%6.1f, T = %4.1f"
|
||
|
% (np.min(stimamp), np.max(stimamp), h.celsius)
|
||
|
)
|
||
|
)
|
||
|
|
||
|
for i, V in enumerate(stimamp):
|
||
|
stim = {}
|
||
|
stim["NP"] = 1
|
||
|
stim["Sfreq"] = 1 # stimulus frequency
|
||
|
stim["delay"] = 5
|
||
|
stim["dur"] = 100
|
||
|
stim["amp"] = V
|
||
|
stim["PT"] = 0.0
|
||
|
self.vcPost.amp2 = V
|
||
|
self.vec["IChan"].record(self.vcPost._ref_i, sec=self.soma)
|
||
|
self.vec["V"].record(self.soma()._ref_v, sec=self.soma)
|
||
|
self.vec["time"].record(h._ref_t)
|
||
|
# print
|
||
|
h.tstop = self.vcPost.dur1 + self.vcPost.dur2 + self.vcPost.dur3
|
||
|
h.finitialize(v_init)
|
||
|
h.run()
|
||
|
self.t = np.array(self.vec["time"])
|
||
|
self.ichan = np.array(self.vec["IChan"])
|
||
|
self.v = np.array(self.vec["V"])
|
||
|
self.p1.plot(self.t, self.ichan, pen=pg.mkPen((i, len(stimamp) * 1.5)))
|
||
|
self.p3.plot(self.t, self.v, pen=pg.mkPen((i, len(stimamp) * 1.5)))
|
||
|
(self.ivss[1, i], r2) = Util.measure(
|
||
|
"mean", self.t, self.ichan, tdelay + tstep[0] - 10.0, tdelay + tstep[0]
|
||
|
)
|
||
|
(self.ivmin[1, i], r2) = Util.measure(
|
||
|
"min", self.t, self.ichan, tdelay + 0.1, tdelay + tstep[0] / 5.0
|
||
|
)
|
||
|
(self.ivmax[1, i], r2) = Util.measure(
|
||
|
"max", self.t, self.ichan, tdelay + 0.1, tdelay + tstep[0] / 5.0
|
||
|
)
|
||
|
self.ivss[0, i] = V
|
||
|
self.ivmin[0, i] = V
|
||
|
self.ivmax[0, i] = V
|
||
|
self.p2.plot(
|
||
|
self.ivss[0, :],
|
||
|
self.ivss[1, :],
|
||
|
symbol="o",
|
||
|
symbolSize=4.0,
|
||
|
pen=pg.mkPen(color),
|
||
|
)
|
||
|
self.p2.plot(
|
||
|
self.ivmax[0, :],
|
||
|
self.ivmax[1, :],
|
||
|
symbol="t",
|
||
|
symbolSize=4.0,
|
||
|
pen=pg.mkPen(color),
|
||
|
)
|
||
|
self.p5.plot(
|
||
|
self.ivmin[0, :],
|
||
|
self.ivmin[1, :],
|
||
|
symbol="s",
|
||
|
symbolSize=4.0,
|
||
|
pen=pg.mkPen(color),
|
||
|
)
|
||
|
|
||
|
print(export)
|
||
|
if export:
|
||
|
exporter = pg.exporters.MatplotlibExporter(self.p1)
|
||
|
print("exporting: " + "%s_traces.svg" % modfile)
|
||
|
exporter.export(fileName="%s_traces.pdf" % modfile)
|
||
|
exporter = pg.exporters.MatplotlibExporter(self.p3)
|
||
|
exporter.export("%s_command.pdf" % modfile)
|
||
|
exporter = pg.exporters.MatplotlibExporter(self.p2)
|
||
|
exporter.export("%s_IV.pdf" % modfile)
|
||
|
|
||
|
def computeKinetics(self, ch):
|
||
|
pass
|
||
|
|
||
|
|
||
|
def getmechs():
|
||
|
mechs = []
|
||
|
for n in dir(nrn):
|
||
|
o = getattr(nrn, n)
|
||
|
if str(o) == str(nrn.Mechanism):
|
||
|
mechs.append(n)
|
||
|
return mechs
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
mechs = getmechs()
|
||
|
if len(sys.argv) < 2:
|
||
|
|
||
|
print("\n\nUsage: python test_mechanisms.py <mechname>")
|
||
|
print(" Available mechanisms:")
|
||
|
|
||
|
linelen = 0
|
||
|
for i, n in enumerate(mechs):
|
||
|
if n in nottestablemechs: # 'Mechanism':
|
||
|
continue
|
||
|
print("%20s" % n, end=" ")
|
||
|
linelen += 20
|
||
|
if linelen > 80:
|
||
|
print("")
|
||
|
|
||
|
linelen = 0
|
||
|
sys.exit(1)
|
||
|
|
||
|
if sys.argv[1:] in nottestablemechs:
|
||
|
exit()
|
||
|
export = False
|
||
|
if len(sys.argv) > 2:
|
||
|
if sys.argv[2] == "export":
|
||
|
export = True
|
||
|
|
||
|
if sys.argv[1] == "all":
|
||
|
for n in mechs:
|
||
|
if n in nottestablemechs:
|
||
|
print(("Skipping %s" % n))
|
||
|
continue
|
||
|
else:
|
||
|
ck = ChannelKinetics(n)
|
||
|
else:
|
||
|
ck = ChannelKinetics(sys.argv[1], export=export)
|
||
|
|
||
|
if sys.flags.interactive == 0:
|
||
|
pg.QtGui.QApplication.exec_()
|