Thanks so much, Ted. This toy model is officially working. I used a VecStim artificial cell to stimulate a NetStim artificial cell, which in turn stimulates a biophysical neuron. Here is the code for the network setup:
Code: Select all
begintemplate Cell_Cell
public is_art
public init, topol, basic_shape, subsets, geom, biophys, geom_nseg, biophys_inhomo
public synlist, x, y, z, position, connect2target
public soma
public all
objref synlist
proc init() {
topol()
subsets()
geom()
biophys()
geom_nseg()
synlist = new List()
synapses()
x = y = z = 0 // only change via position
}
create soma
proc topol() { local i
basic_shape()
}
proc basic_shape() {
soma {pt3dclear() pt3dadd(0, 0, 0, 1) pt3dadd(15, 0, 0, 1)}
}
objref all
proc subsets() { local i
objref all
all = new SectionList()
soma all.append()
}
proc geom() {
}
external lambda_f
proc geom_nseg() {
}
proc biophys() {
soma {
insert hh
gnabar_hh = 0.12
gkbar_hh = 0.036
gl_hh = 0.0003
el_hh = -54.3
}
}
proc biophys_inhomo(){}
proc position() { local i
soma for i = 0, n3d()-1 {
pt3dchange(i, $1-x+x3d(i), $2-y+y3d(i), $3-z+z3d(i), diam3d(i))
}
x = $1 y = $2 z = $3
}
obfunc connect2target() { localobj nc //$o1 target point process, optional $o2 returned NetCon
soma nc = new NetCon(&v(1), $o1)
nc.threshold = 10
if (numarg() == 2) { $o2 = nc } // for backward compatibility
return nc
}
objref syn_
proc synapses() { //this is the result of my adding one synapse in the GUI
/* ExpSyn0 */ soma syn_ = new ExpSyn(0.6) synlist.append(syn_)
}
func is_art() { return 0 }
endtemplate Cell_Cell
begintemplate NetStim_NetStim
public pp, connect2target, x, y, z, position, is_art
objref pp
proc init() {
pp = new NetStim()
pp.start = -1
pp.number = 25
pp.noise = 0.5
}
func is_art() { return 1 }
obfunc connect2target() { localobj nc
nc = new NetCon(pp, $o1)
if (numarg() == 2) { $o2 = nc }
return nc
}
proc position(){x=$1 y=$2 z=$3}
endtemplate NetStim_NetStim
//VecStim template
begintemplate vs_VecStim
public pp, connect2target, x, y, z, position, is_art
objref pp
proc init() {
pp = new VecStim()
}
func is_art() { return 1 }
obfunc connect2target() { localobj nc
nc = new NetCon(pp, $o1)
if (numarg() == 2) { $o2 = nc }
return nc
}
proc position(){x=$1 y=$2 z=$3}
endtemplate vs_VecStim
//Network specification interface
objref cells, nclist, netcon
{cells = new List() nclist = new List()}
func cell_append() {cells.append($o1) $o1.position($2,$3,$4)
return cells.count - 1
}
//this function creates a connection between two cells, and adds it to the list of netcons
func nc_append() {//srcindex, tarcelindex, synindex
if ($3 >= 0) {
//cells.object($1) picks out the $1 element of the 'cells' list; then you connect this cell to the target specified in the argument to 'connect2target,' in this case the $2 element of the 'cells' list, this cell might have multiple synapses, so you connect it to the $3 synapse on that cell
netcon = cells.object($1).connect2target(cells.object($2).synlist.object($3))
//this just specifies the weight and delay associated with this particular netcon
netcon.weight = $4 netcon.delay = $5
}else{
netcon = cells.object($1).connect2target(cells.object($2).pp)
netcon.weight = $4 netcon.delay = $5
}
nclist.append(netcon)
return nclist.count - 1
}
//Network instantiation
//so this just adds the first (and only) HH cell to the network, and specifies its location
/* Cell0 */ cell_append(new Cell_Cell(), -35, -48, 0)
//this adds a netstim cell to the network
/* NetStim1 */ cell_append(new NetStim_NetStim(), 5, -8, 0)
//now add a vecstim
cell_append(new vs_VecStim(),0,0,0)
//this adds a connection from Cell #1 (netstim) to Cell #0 (HH cell), to the 0th synapse on Cell #0, with a weight of 0 and a delay of 1 (ms?)
/* NetStim1 -> Cell0.ExpSyn0 */ nc_append(1, 0, 0, 0.5,1)
//add connection from Cell #2 (VecStim) to Cell #1 (netstim)
//(important to make third entry '-1' (see pg. 328 NEURON Book)
nc_append(2,1,-1,1,0)
I got the template for the VecStim by loading "vecevent.ses" in nrn\examples\nrniv\netcon and then having the network builder generate code. And here is the code for the simulation and plotting:
Code: Select all
v_init = -65
tstop = 5000
dt=0.025
objref rect,recv
rect = new Vector()
recv = new Vector()
//make *sure* to include '.object' when it's a list; otherwise NEURON will just crash
recv.record(&cells.object[0].soma.v(0.5))
rect.record(&t)
//prepare to record and display spike trains (from p. 338 in The NEURON Book)
objref netcon,vec,spikes,nil,graster
proc preprasterplot(){
spikes = new List()
//for i=0,cells.count()-1{
vec = new Vector()
netcon = new NetCon(&cells.object(0).soma.v,nil)
netcon.record(vec)
spikes.append(vec)
//}
objref netcon, vec
graster = new Graph(0)
graster.view(0,0,tstop,cells.count(), 300,105,300.48,200.32)
}
preprasterplot()
objref spikey
proc showraster(){
graster.erase_all()
//for i = 0,cells.count()-1 {
spikey = spikes.object(0).c
spikey.fill(1)
spikey.mark(graster,spikes.object(0), "|", 6)
//}
objref spikey
}
objref vec
vec = new Vector(4)
//define the times at which you want to stimulate a barrage of activity
vec.x[0]=1000
vec.x[1]=2000
vec.x[2]=3000
vec.x[3]=4000
cells.object(2).pp.play(vec)
proc go(){
stdinit()
run()
showraster()
}
The output of the biophysical neuron of the biophysical neuron shows that the simulation is working as intended, inducing bursts of activity at 1000, 2000, 3000, and 4000 ms:
One thing to note is that when I set netstim.start=1e9, I could not elicit any spiking. Apparently netstim will not respond to any input from vecstim until after the time specified by netstim.start. Therefore setting netstim.start=-1 solved the problem. Thanks for all the help, Ted. I think VecStim should be able to solve the memory problems in the code I mentioned at the start of this post...