NEURON Programming Tutorial #4 |
The final code for this tutorial is quite long and complicated, so only specific examples are shown in the text. The complete, runable code is supplied in two separate files: prog4.hoc and prog4.ses. You should copy these files and examine prog4.hoc once you have gone through the tutorial (prog4.ses is just a session file that sets up some shape and space plots for you).
A template is an object definition--it defines a prototype of an object from which we can create multiple copies. After defining the template, we must declare the object variable that we will use to reference the objects, just like we have in the past with the IClamp and AlphaSynapse. Then, we can create a new instance of the object from the template that is an exact copy of the template. After we create the object from the template, we can either use it as it is or we can modify it to fit our needs.
For our system, we turn the cell we created in the last tutorial into a template from which we can create all four cells. The structure of a template is as follows:
begintemplate name code endtemplate namewhere name is the name of the template you want to create, and code is any program commands that you want the template to include. In the code section, there are several procedures and commands that have special significance: public, external, and init().
The public statement is used to tell NEURON what parts of the template can be accessed outside of the template definition. Normally, if there are no public names, then the code inside the template is completely private and nothing, aside from the name of the template itself, is accessible from the rest of the program code. For example, if we create a neuron template and we want to be able to put a pulse stimulus in the soma of the cell we create, we would need to give access to the soma section via the public command:
begintemplate Cell public soma create soma, axon, dend[1] proc init() { ndend = $1 create soma, axon, dend[ndend] soma { nseg = 1 diam = 100 L = 100 insert hh } axon { nseg = 50 diam = 10 L = 5000 insert hh } for i = 0, ndend-1 dend[i] { nseg = 5 diam = 25 L = 500 insert pas } connect axon(1), soma(0) for i = 0, ndend-1 connect dend[i](0), soma(1) } endtemplate CellThis example allows access to soma outside of the template, so we could create our four cells and insert the pulse stimulus as follows:
ncells = 3 objectvar cell, precells[ncells] cell = new Cell(3) for i = 0, ncells-1 { precells[i] = new Cell(2) } objectvar stim[ncells] for i = 0, ncells-1 precells[i].soma { stim[i] = new IClamp(0.5) stim[i].dur = 0.1 stim[i].amp = 500 }After declaring the cell with the objectvar command and creating the object with the new command, we can access the soma using dot notation (e.g., precells[2].soma.L is the length of the soma in one of the cells we created).
This example also illustrates the init() procedure. Most templates will have a special procedure called init() which is automatically called when a new object is created from the template. This is very useful to initialize the newly created object. Since arguments can be passed to init(), you can affect the initialization of the object via the parameters you pass to the new command. For example, the cell = new Cell(3) command will create a new object from the template Cell [Note that case is important]. The parameter "3" is passed to the init() procedure in the template, and init() uses this information to create a cell with three dendrites.
The external is not used in this example. It would follow the public statement and list any externally defined functions used in the body of the template.
Adding synaptic connections
To connect multiple cells together via synapses, we need to create a
link between an action potential in a pre-synaptic cell and a
conductance change in a post-synaptic cell.
For our example, we are not interested in the details of calcium
concentration in the synaptic terminals, neurotransmitter release or
post-synaptic receptor binding affinities; rather, we only want an
action potential at the end of the pre-synaptic axon to trigger a
simple postsynaptic conductance change (in the form of an alpha
function) after a short synaptic delay. We can do this by using a
NetCon object and a suitable point process for the synapse. A Network Connection (NetCon) object defines a synaptic connection
between a source and a target. One syntax for creating a new NetCon object is:
section netcon = new Netcon(&v(x), target, threshold, delay, weight)
When the source variable, in this case the membrane voltage, v at point x of section, passes threshold in the positive direction at time t-delay, the target will receive an event (ie the occurrence of a presynaptic action potential) at time t along with weight information (the weight is typically the maximum synaptic conductance). The target is usually a synaptic point process that generates a conductance change in response to a presynaptic action potential. In the following we will use the ExpSyn point process, which implements a conductance change that is an instantaneous increase, followed by an exponential decay.
In our template, we need to add the the post-synaptic ExpSyn point process to each dendrite. Just as with other point processes, we must first declare the object variables for each point process and then create the new point processes. We can then initialize the point process parameters. The presynaptic NetCon object will be called presyn, and the postsynaptic ExpSyn objects will be called postsyn. Our template now looks like:
begintemplate Cell public soma, axon, dend, presyn, postsyn create soma, axon, dend[1] objectvar postsyn[1] objectvar presyn proc init() {local i ndend = $1 create soma, axon, dend[ndend] objectvar postsyn[ndend] objectvar presyn soma { nseg = 1 diam = 100 L = 100 insert hh } axon { nseg = 50 diam = 10 L = 5000 insert hh } for i = 0, ndend-1 dend[i] { nseg = 5 diam = 25 L = 500 insert pas } connect axon(1), soma(0) for i = 0, ndend-1 connect dend[i](0), soma(1) for i = 0, ndend-1 dend[i] { postsyn[i] = new ExpSyn(0.8) postsyn[i].tau = 0.1 postsyn[i].e = 15 } } endtemplate Cell
for i = 0,ncells-1 { precells[i].axon precells[i].presyn = new NetCon(&v(0), cell.postsyn[i], -20, 1, 2.8) }Now when an AP reaches threshold (-20mV) at the "0" end of the axon of pre-synaptic cell i and the synaptic delay (1msec) has passed, the synaptic conductance of cell.postsyn[i] is increased by by 2.8uS.
To see the complete cell template and how to create and connect the four cells, examine the file prog4.hoc
. Before running the tutorial we need to position our cells sensibly in 3-D space so that we can see them in a shape display.
We can use two functions to reposition each section: pt3dclear() and pt3dadd(). The first, pt3dclear(), will erase any 3-D positioning information associated with the section. The second, pt3dadd(), takes four arguments (X, Y, Z, and diam) and will add a new coordinate to the section. Usually there are coordinates for each end of the section which can be set by making two calls to pt3dadd()--once for the "0" end of the section and once for the "1" end of the section.
In the example program that accompanies this tutorial, prog4.hoc, we have positioned the cells so that the axons of the three pre-synaptic cells are next to the dendrite of the post-synaptic cell that they excite.
Modified by Bruce Graham (b.graham@cs.stir.ac.uk)