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.
413 lines
13 KiB
413 lines
13 KiB
2 years ago
|
"""
|
||
|
Layout:
|
||
|
|
||
|
if __name__==__main__ handles cmd args, instantiates test, runs it, displays results
|
||
|
|
||
|
run_trial(): defines a model and then runs the test using preset params in hoc and return the info to the class
|
||
|
SGCInputTest:
|
||
|
__init__ : defines many static variables
|
||
|
run(): calls delivers information to the run_trial() function and the recieved information of a single run
|
||
|
back and stores it as an exstensible list in the class
|
||
|
show(): displays graphs depending on the graph options selected below it and displayed in a printout
|
||
|
|
||
|
"""
|
||
|
import argparse
|
||
|
import numpy as np
|
||
|
import pyqtgraph as pg
|
||
|
from neuron import h
|
||
|
from cnmodel.protocols import Protocol
|
||
|
from cnmodel import cells
|
||
|
from cnmodel.util import sound
|
||
|
from cnmodel.util import custom_init
|
||
|
import cnmodel.util.pynrnutilities as PU
|
||
|
from cnmodel import data
|
||
|
|
||
|
try:
|
||
|
from tqdm import trange
|
||
|
except ImportError as err:
|
||
|
raise ImportError("Please 'pip install tqdm' to allow for progress bar")
|
||
|
|
||
|
species = "rat" # tables for other species do not yet exist
|
||
|
|
||
|
|
||
|
def run_trial(cell, info):
|
||
|
"""
|
||
|
info is a dict
|
||
|
"""
|
||
|
if cell == "bushy":
|
||
|
post_cell = cells.Bushy.create(species=species)
|
||
|
elif cell == "tstellate":
|
||
|
post_cell = cells.TStellate.create(species=species)
|
||
|
elif cell == "octopus":
|
||
|
post_cell = cells.Octopus.create(species=species)
|
||
|
elif cell == "dstellate":
|
||
|
post_cell = cells.DStellate.create(species=species)
|
||
|
elif cell == "tuberculoventral":
|
||
|
post_cell = cells.DStellate.create(species=species)
|
||
|
elif cell == "pyramidal":
|
||
|
post_cell = cells.Pyramidal.create(species=species)
|
||
|
else:
|
||
|
raise ValueError("cell %s is not yet implemented for PSTH testing" % cell)
|
||
|
pre_cells = []
|
||
|
synapses = []
|
||
|
for nsgc, sgc in enumerate(range(info["n_sgc"])):
|
||
|
pre_cells.append(cells.DummySGC(cf=info["cf"], sr=info["sr"]))
|
||
|
synapses.append(pre_cells[-1].connect(post_cell, type=info["synapse_type"]))
|
||
|
synapses[
|
||
|
-1
|
||
|
].terminal.relsite.Dep_Flag = False # no depression in these simulations
|
||
|
pre_cells[-1].set_sound_stim(
|
||
|
info["stim"], seed=info["seed"] + nsgc, simulator=info["simulator"]
|
||
|
)
|
||
|
|
||
|
# stim = insert_current_clamp(post_cell.soma)
|
||
|
Vm = h.Vector()
|
||
|
Vm.record(post_cell.soma(0.5)._ref_v)
|
||
|
rtime = h.Vector()
|
||
|
rtime.record(h._ref_t)
|
||
|
h.tstop = 1e3 * info["run_duration"] # duration of a run
|
||
|
h.celsius = info["temp"]
|
||
|
h.dt = info["dt"]
|
||
|
post_cell.cell_initialize()
|
||
|
info["init"](v_init=-60)
|
||
|
h.t = 0.0
|
||
|
h.run()
|
||
|
pre_cells_data = [x._spiketrain for x in pre_cells]
|
||
|
|
||
|
return {"time": np.array(rtime), "vm": list(Vm), "pre_cells": pre_cells_data}
|
||
|
|
||
|
|
||
|
# stim = insert_current_clamp(post_cell.soma)
|
||
|
def insert_current_clamp(sec):
|
||
|
"""
|
||
|
:param sec: to attach too
|
||
|
dur: ms
|
||
|
amp: nA
|
||
|
delay: ms
|
||
|
:return: stim needs to be put in a variable to stay alive
|
||
|
"""
|
||
|
stim = h.IClamp(0.5, sec=sec)
|
||
|
stim.dur = 90
|
||
|
stim.amp = -0.2
|
||
|
stim.delay = 2
|
||
|
return stim
|
||
|
|
||
|
|
||
|
class SGCTestPSTH(Protocol):
|
||
|
"""
|
||
|
Tests a Single cell with input recieved from the SGC
|
||
|
|
||
|
__init__: almost all parameters can be modified
|
||
|
run(): simply loops over the run_trial() function and stores the results just
|
||
|
show(): constructs the graphs using other functions
|
||
|
|
||
|
"""
|
||
|
|
||
|
def __init__(
|
||
|
self,
|
||
|
temp=34.0,
|
||
|
seed=5908035,
|
||
|
nrep=10,
|
||
|
stimulus="tone",
|
||
|
simulator="cochlea",
|
||
|
n_sgc=12,
|
||
|
debug=True,
|
||
|
cell="bushy",
|
||
|
):
|
||
|
"""
|
||
|
:param temp: (float) must be at 34 for default pyramidal cells
|
||
|
:param dt: (float) determine hoc resolution
|
||
|
:param seed: (int) contributes to randomization, needs to be changed to see different results (reduce this
|
||
|
number if you keep getting a timeout error
|
||
|
:param nrep: (int) number of presentations !!must be changed in the __name__ function if not calling from cmd line!!
|
||
|
:param stimulus: (str) must be 'tone'
|
||
|
:param simulator: (str) currently using cochlea instead of matlab
|
||
|
:param n_sgc:(int) This is the number of SGC fibers that connect to the post synaptic cell
|
||
|
:param debug: (bool) controls most of the terminal printouts is on by default
|
||
|
:param cell: (str) cell type !!must be changed in the __name__ function if not calling from cmd line!!
|
||
|
"""
|
||
|
super().__init__()
|
||
|
assert stimulus == "tone"
|
||
|
assert cell in [
|
||
|
"bushy",
|
||
|
"tstellate",
|
||
|
"octopus",
|
||
|
"dstellate",
|
||
|
"tuberculoventral",
|
||
|
"pyramidal",
|
||
|
]
|
||
|
self.debug = debug
|
||
|
self.nrep = nrep
|
||
|
self.stimulus = stimulus
|
||
|
self.run_duration = 0.30 # in seconds
|
||
|
self.pip_duration = 0.05 # in seconds
|
||
|
self.pip_start = [0.1] # in seconds
|
||
|
self.Fs = 100e3 # in Hz
|
||
|
self.f0 = 13000.0 # stimulus in Hz
|
||
|
self.cf = 13000.0 # SGCs in Hz
|
||
|
self.fMod = 100.0 # mod freq, Hz
|
||
|
self.dMod = 0.0 # % mod depth, Hz
|
||
|
self.dbspl = 55.0
|
||
|
self.simulator = simulator
|
||
|
self.sr = 2 # set SR group
|
||
|
self.seed = seed
|
||
|
self.temp = temp
|
||
|
self.dt = 0.025
|
||
|
self.cell = cell
|
||
|
self.synapse_type = "multisite"
|
||
|
|
||
|
if self.stimulus == "tone":
|
||
|
self.stim = sound.TonePip(
|
||
|
rate=self.Fs,
|
||
|
duration=self.run_duration,
|
||
|
f0=self.f0,
|
||
|
dbspl=self.dbspl,
|
||
|
ramp_duration=2.5e-3,
|
||
|
pip_duration=self.pip_duration,
|
||
|
pip_start=self.pip_start,
|
||
|
)
|
||
|
|
||
|
if not n_sgc:
|
||
|
n_sgc = data.get(
|
||
|
"convergence", species="mouse", post_type=self.cell, pre_type="sgc"
|
||
|
)[0]
|
||
|
self.n_sgc = int(np.round(n_sgc))
|
||
|
# convert nS to uS for NEURON
|
||
|
|
||
|
self.vms = [None for n in range(self.nrep)]
|
||
|
self.synapses = [None for n in range(self.nrep)]
|
||
|
self.pre_cells = [None for n in range(self.nrep)]
|
||
|
self.time = [None for n in range(self.nrep)]
|
||
|
# debug function reports a print out of various information about the run
|
||
|
if self.debug:
|
||
|
print("SGCInputTest Created")
|
||
|
print()
|
||
|
print("Test parameters")
|
||
|
print("#" * 70)
|
||
|
print(f"Running test of {cell} cell synapse with Simulated SGC fibers")
|
||
|
print()
|
||
|
print(f"Run Conditions: Run Time: {self.run_duration}s,")
|
||
|
print(f" Run Temp: {self.temp} ")
|
||
|
print(f" Sgc Connections {n_sgc}")
|
||
|
print(f" Number of Presentations: {nrep}")
|
||
|
print()
|
||
|
print(f"Stimulus Conditions: Type: {stimulus}")
|
||
|
print(f" Stim Duration: {self.pip_duration}s")
|
||
|
print(f" Characteristic F: {self.cf}hz")
|
||
|
print(f" Stim Start:{str(self.pip_start)}s")
|
||
|
|
||
|
def run(self):
|
||
|
super().run()
|
||
|
info = {
|
||
|
"n_sgc": self.n_sgc,
|
||
|
"stim": self.stim,
|
||
|
"simulator": self.simulator,
|
||
|
"cf": self.cf,
|
||
|
"sr": self.sr,
|
||
|
"seed": self.seed,
|
||
|
"run_duration": self.run_duration,
|
||
|
"synapse_type": self.synapse_type,
|
||
|
"temp": self.temp,
|
||
|
"dt": self.dt,
|
||
|
"init": custom_init,
|
||
|
}
|
||
|
for nr in trange(self.nrep):
|
||
|
info["seed"] = self.seed + self.n_sgc + nr + 3
|
||
|
res = run_trial(self.cell, info)
|
||
|
# res contains: {'time': time, 'vm': list(Vm), 'pre_cells': pre_cells._spiketrain,}
|
||
|
self.pre_cells[nr] = res["pre_cells"]
|
||
|
self.time[nr] = res["time"]
|
||
|
self.vms[nr] = res["vm"]
|
||
|
|
||
|
def show(self):
|
||
|
"""
|
||
|
Creates a single page graph that contains all of the graphs based on the graphical functions in the class
|
||
|
|
||
|
"""
|
||
|
self.win = pg.GraphicsWindow()
|
||
|
self.win.setBackground("w")
|
||
|
p1 = self.stimulus_graph()
|
||
|
p2 = self.an_spikes_graph()
|
||
|
p3 = self.cell_spikes_graph()
|
||
|
p4 = self.voltage_graph()
|
||
|
p6 = (
|
||
|
self.an_psth_graph()
|
||
|
) # requires that an_spikes_graph() has been called before
|
||
|
p7 = (
|
||
|
self.cell_psth_graph()
|
||
|
) # requires that cell_spikes_graph() has been called before
|
||
|
|
||
|
# links x axis
|
||
|
p1.setXLink(p1)
|
||
|
p2.setXLink(p1)
|
||
|
p3.setXLink(p1)
|
||
|
p4.setXLink(p1)
|
||
|
self.win.show()
|
||
|
if self.debug:
|
||
|
print("finished")
|
||
|
|
||
|
############# Graph options to be included in the show() method ###################
|
||
|
def stimulus_graph(self):
|
||
|
p1 = self.win.addPlot(
|
||
|
title="Single Tone Stimulus", row=0, col=0, labels={"bottom": "T (ms)"}
|
||
|
)
|
||
|
p1.plot(self.stim.time * 1000, self.stim.sound, pen=pg.mkPen("k", width=0.75))
|
||
|
return p1
|
||
|
|
||
|
def an_spikes_graph(self):
|
||
|
p2 = self.win.addPlot(
|
||
|
title="AN spikes",
|
||
|
row=1,
|
||
|
col=0,
|
||
|
labels={"bottom": "T (ms)", "left": "AN spikes (first trial)"},
|
||
|
)
|
||
|
self.all_xan = []
|
||
|
for nr in range(self.nrep):
|
||
|
xan = []
|
||
|
yan = []
|
||
|
for k in range(len(self.pre_cells[nr])):
|
||
|
r = self.pre_cells[nr][k]
|
||
|
xan.extend(r)
|
||
|
self.all_xan.extend(r)
|
||
|
yr = k + np.zeros_like(r) + 0.2
|
||
|
yan.extend(yr)
|
||
|
c = pg.PlotCurveItem()
|
||
|
xp = np.repeat(np.array(xan), 2)
|
||
|
yp = np.repeat(np.array(yan), 2)
|
||
|
yp[1::2] = yp[::2] + 0.6
|
||
|
c.setData(
|
||
|
xp.flatten(),
|
||
|
yp.flatten(),
|
||
|
connect="pairs",
|
||
|
width=1.0,
|
||
|
pen=pg.mkPen("k", width=1.5),
|
||
|
)
|
||
|
p2.addItem(c)
|
||
|
|
||
|
return p2
|
||
|
|
||
|
def cell_spikes_graph(self):
|
||
|
p3 = self.win.addPlot(
|
||
|
title="Pyramidal Cell Spikes",
|
||
|
row=2,
|
||
|
col=0,
|
||
|
labels={"bottom": "T (ms)", "left": "Trial #"},
|
||
|
)
|
||
|
xcn = []
|
||
|
ycn = []
|
||
|
for k in range(self.nrep):
|
||
|
bspk = PU.findspikes(self.time[k], self.vms[k], -35.0)
|
||
|
xcn.extend(bspk)
|
||
|
yr = k + np.zeros_like(bspk) + 0.2
|
||
|
ycn.extend(yr)
|
||
|
d = pg.PlotCurveItem()
|
||
|
xp = np.repeat(np.array(xcn), 2)
|
||
|
yp = np.repeat(np.array(ycn), 2)
|
||
|
yp[1::2] = yp[::2] + 0.6
|
||
|
d.setData(
|
||
|
xp.flatten(), yp.flatten(), connect="pairs", pen=pg.mkPen("k", width=1.5)
|
||
|
)
|
||
|
self.xcn = xcn
|
||
|
self.ycn = ycn
|
||
|
p3.addItem(d)
|
||
|
|
||
|
return p3
|
||
|
|
||
|
def voltage_graph(self):
|
||
|
p4 = self.win.addPlot(
|
||
|
title="Pyramidal Vm",
|
||
|
row=0,
|
||
|
col=1,
|
||
|
labels={"bottom": "T (ms)", "left": "Vm (mV)"},
|
||
|
)
|
||
|
if self.nrep > 5:
|
||
|
display = 3
|
||
|
else:
|
||
|
display = self.nrep
|
||
|
for nr in range(display):
|
||
|
p4.plot(
|
||
|
self.time[nr],
|
||
|
self.vms[nr],
|
||
|
pen=pg.mkPen(pg.intColor(nr, self.nrep), hues=self.nrep, width=1.0),
|
||
|
)
|
||
|
return p4
|
||
|
|
||
|
def an_psth_graph(self):
|
||
|
p6 = self.win.addPlot(
|
||
|
title="AN PSTH",
|
||
|
row=1,
|
||
|
col=1,
|
||
|
labels={"bottom": "T (ms)", "left": "# of Spikes(0.75ms"},
|
||
|
)
|
||
|
bins = np.arange(60, 200, 0.5)
|
||
|
(hist, binedges) = np.histogram(self.all_xan, bins)
|
||
|
curve6 = p6.plot(
|
||
|
binedges,
|
||
|
hist,
|
||
|
stepMode=True,
|
||
|
fillBrush=(0, 0, 0, 255),
|
||
|
brush=pg.mkBrush("k"),
|
||
|
fillLevel=0,
|
||
|
)
|
||
|
return p6
|
||
|
|
||
|
def cell_psth_graph(self):
|
||
|
p7 = self.win.addPlot(
|
||
|
title="Pyramidal PSTH",
|
||
|
row=2,
|
||
|
col=1,
|
||
|
labels={"bottom": "T (ms)", "left": "# of Spikes(0.75ms)"},
|
||
|
)
|
||
|
bins = np.arange(60, 200, 0.5)
|
||
|
(hist, binedges) = np.histogram(self.xcn, bins)
|
||
|
curve7 = p7.plot(
|
||
|
binedges,
|
||
|
hist,
|
||
|
stepMode=True,
|
||
|
fillBrush=(0, 0, 0, 255),
|
||
|
brush=pg.mkBrush("k"),
|
||
|
fillLevel=0,
|
||
|
)
|
||
|
return p7
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
parser = argparse.ArgumentParser(
|
||
|
description="Compute AN only PSTH in postsynaptic cell"
|
||
|
)
|
||
|
parser.add_argument(
|
||
|
type=str,
|
||
|
dest="cell",
|
||
|
default="pyramidal",
|
||
|
choices=[
|
||
|
"bushy",
|
||
|
"tstellate",
|
||
|
"dstellate",
|
||
|
"octopus",
|
||
|
"tuberculoventral",
|
||
|
"pyramidal",
|
||
|
],
|
||
|
help="Select target cell",
|
||
|
)
|
||
|
parser.add_argument(
|
||
|
"-n",
|
||
|
"--nrep",
|
||
|
type=int,
|
||
|
dest="nrep",
|
||
|
default=1,
|
||
|
help="Set number of repetitions",
|
||
|
)
|
||
|
|
||
|
args = parser.parse_args()
|
||
|
|
||
|
cell = args.cell
|
||
|
nrep = args.nrep
|
||
|
prot = SGCTestPSTH(nrep=100, cell=cell)
|
||
|
prot.run()
|
||
|
prot.show()
|
||
|
|
||
|
import sys
|
||
|
|
||
|
if sys.flags.interactive == 0:
|
||
|
pg.QtGui.QApplication.exec_()
|