NEURON Programming Tutorial #4

Back to Tutorial Home Page


NEURON Programming Tutorial #4

Introduction

We are finally ready to finish the multiple cell model we started in the first tutorial. In this tutorial, we will create a template of the cell from which we can create multiple new copies of the cell, and then we will connect the cells together using a pair of new point processes that mimic the action of a pre- and post-synaptic connection.

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).

Templates

In the last tutorial, we finished the first cell that we need in our four cell system. Now, we need to copy it three more times, and connect the cells together. NEURON provides us with an simple way to create multiple copies of the same cell: templates.

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 name
where 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 Cell
This 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

Connecting our cells

To finish the synapse, we need to connect the pre- and post-synaptic objects together by creating a new NetCon object. This takes place outside of the template, as follows:

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.

Positioning cells in 3-D

Each time we create a new section and connect it to others, NEURON places the section in a 3-D space and assigns an X, Y and Z coordinate to each end of the section. When creating multiple cells, as we have above, each cell is given a different Z coordinate for all of its sections. The X and Y coordinates of each cell are determined by how the individual sections are connected. This makes viewing the cells difficult since they are not arranged how we would normally think of them. Fortunately, NEURON provides a way to reposition each section in the 3-D space.

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.

Running the tutorial code

Run prog4.hoc in NEURON. The associated session file, prog4.ses will result in several shape and space plots being produced. Click Init & Run to see the three presynaptic cells stimulate and produce an actional potential in the postsynaptic cell. A colour-coded display of the membrane potential in the four cells can be obtained by selecting Shape Plot from the background popup menu (righ mouse button) of the Shape window in which the cells are drawn. Rerun the simulation to see this in action.

Where to go from here

There are many more commands, functions and options in NEURON, and currently the best place to learn about them is the help system. There are also several manuals, and, hopefully, there will soon be a book on NEURON. Local copies of documentation can be found here"


Kevin E. Martin (martin@cs.unc.edu)

Modified by Bruce Graham (b.graham@cs.stir.ac.uk)