NEURON Programming Tutorial #1

Back to Tutorial Home Page


NEURON Programming Tutorial #1

Introduction

NEURON is an extensible nerve modeling and simulation program. It allows you to create complex nerve models by connecting multiple one-dimensional sections together to form arbitrary cell morphologies, and allows you to insert multiple membrane properties into these sections (including channels, synapses, ionic concentrations, and counters). The interface was designed to present the neural modeler with a intuitive environment and hide the details of the numerical methods used in the simulation.

This set of tutorials will take you, step by step, through the process of creating a complex simulation. It starts with the basics: how to create a very simple model, how to run the simulator, how to display the simulation results. Then, it moves into the more advanced topics of adding complexity to the models and use of different types of graphs to display the results. Finally it shows you how to create new templates to include in a cell library, how to connect multiple cells together, and how to add new membrane mechanisms to the simulator.

It is always good to have a final product in mind when we start the modeling task, so here is ours: We are trying to model a simple four neuron system with three of the cells making synaptic connections to the fourth. Each of these cells have basically the same morphology: a single axon with minimal arborization at the end and several main dendritic trunks with complex branching. We believe there are Hodgkin-Huxley type ion channels in the axon and possibly in the soma, but are uncertain what type of channels are in the dendrites. We have intracellular somatic voltage measurements in the post-synaptic cell from current injections in the somas of the three other cells.

Begin at the beginning: How to start the simulator

NEURON is an interpreter which can accept commands directly from the keyboard or from a program you have entered. The easiest way to start the simulator is to select "nrngui" from the "Start->Programs->Neuron" menu, if running under Windows, or to type nrngui at a Unix command prompt. Do this now. A NEURON Main Menu will appear and, under Windows, a terminal window. In the terminal window you should see a prompt that looks like:

oc>
This is the oc> prompt and when you see this, you can enter NEURON commands directly from the keyboard. In the following you will be shown commands that will build a model neuron. Enter these commands at this prompt.

When you need to exit from the simulator, choose "Quit" from the "File" menu in the "NEURON Main Menu".

Creating and accessing sections

The first step in creating our model is to build the neuron's morphology. Cells can usually be described by reducing their complex structures into cylindrical sections. For example, the simplest reduction is to remove the cell's axon and dendrites leaving only the cell body. By modeling only the cell body, you possibly lose a tremendous amount of useful information, but you can always increase the morphological complexity as needed (see Tutorial #2).

From our experimental measurements, we know that our cell to model is approximately 100 um in length and averages about 100 um in diameter. In NEURON, the cell's geometry is described in terms of cylindrical sections. Before we set the section's properties, we must first create a new section, soma, as follows:

create soma
This command creates a new section with the default properties (the number of segments in the section [1], the diameter [500 um], the length [100 um], the capacitance [1 uF/cm^2], the axial resistance used to connect sections together [34.5 ohm-cm] and the membrane voltage [-65 mV]). For our simulation, we need to change one of our soma's properties--the diameter of the section (diam)--but for program clarity, it is also advisable to set the number of segments (nseg) and the length of the section (L).

Since NEURON deals with many different sections each with their own unique name, we must tell NEURON which section we are working on when we want to access a section parameter. There are three ways to do this in NEURON. First we can access the section:

access soma
This tells NEURON that all subsequent references to properties of a section are intended for the soma. Now we can specify the properties we want to set:

nseg = 1
diam = 100
L = 100
The second way to access section properties is to use dot notation. Here, we access the section properties with the section name followed by a "dot" or period (i.e., ".") followed by the property name:

soma.nseg = 1
soma.diam = 100
soma.L = 100
With dot notation, the currently accessed section is not changed.

Methods #1 and #2 can both set and retrieve values. Above, we set the values. One way to retrieve the value is with the print command. If you have a currently accessed section (from the access command), you can print a property of that section with:

print diam
or you can print the property of any section by using the dot notation:

print soma.diam
The third way is to group all of the properties together and preface the group with the section name you want to access. This has the advantage of not changing the currently accessed section (as in method #2):

soma nseg = 1
soma diam = 100
soma L = 100
or you can group multiple properties between braces (this is only useful if you are storing HOC commands in a file, rather than entering them at the command prompt):

soma {
    nseg = 1
    diam = 100
    L = 100
}
The third method is only used to set values.

We will use all three methods of specifying properties in the tutorials, but for tutorial #1 we mainly will use the first method. Thus, the program so far is:

create soma
access soma

nseg = 1
diam = 100
L = 100

Inserting membrane properties

Each section in NEURON has the default properties (see above) automatically inserted, but other mechanisms (e.g., channels) with their own properties must be explicitly inserted into a section. NEURON includes two built-in channel membrane mechanisms: Hodgkin-Huxley channels (hh) and passive channels (pas). Each of these mechanisms can be inserted using the insert command. If there is a currently accessed section, you can insert a new mechanism into that section by:

insert hh
You can also use the third method to insert a new mechanism:

soma insert pas
You can add as many properties into each section as you need for your model.

When you add a new membrane mechanism to a section, you add the new membrane mechanism's properties and their default values to the section. For example, if you add passive channels to the section, you will introduce two new properties to the section: g_pas (specific membrane conductance [S/cm^2]) and e_pas (reversal potential [mV]). For our simulation, we want to insert Hodgkin-Huxley channels into the soma. Since soma is the currently accessed section, we can do this with:

insert hh
The Hodgkin-Huxley channels add the following new properties to the section:

It also adds the following state variables, that can be displayed with the print command:

You can also define other membrane mechanisms with their own properties using the model description language, NMODL, which will not be covered in these tutorials.

To display all of the properties and their current values in a particular section, you can call the psection function. To see the properties of the currently accessed section:

psection()
or for a particular section:

soma psection()
or to list the properties of all sections in the model:

forall psection()
For our model, we can accept the default values for the other properties. Thus, our program looks like:

create soma
access soma

nseg = 1
diam = 100
L = 100

insert hh

Adding point processes

NEURON makes the distinction between mechanisms that are attributed to an entire section (e.g., HH channels) and mechanisms that are associated with a particular point in the section (e.g., voltage clamp or synapse). While the former is most conveniently expressed in terms of per unit area, the point processes are more conveniently expressed in absolute terms (e.g., current injection is usually expressed in terms of nA instead of nA/cm^2). Point processes also differ in that you insert several in the same segment.

In NEURON, point processes are handled as objects which means that to create one you need to first create an object variable to be associated with the object and then create a new object. To declare object variables, you enter the following:

objectvar stim
This creates an object variable named stim, and now you need to create the actual object. Newly created objects need to be associated with a particular section, so we need to either have a currently accessed section or to specify the section name with which the object is to be associated. The optional section name is give first followed by the assignment of the object variable to a new instance of a particular object (in this case a pulse stimulus) with the location of the object in the section given in parentheses. The location is specified with a number between 0 and 1 (inclusive) where the number represents the percent along the section to place the point process. For example:

stim = new IClamp(0.5)
or with the section name:

soma stim = new IClamp(0.5)
Since the currently accessed section in our program is soma, both of these commands will accomplish the same result (i.e., creating a new pulse stimulus in the middle of the soma).

There are several built-in point processes: IClamp and AlphaSynapse are two of them. Additional point processes can be added to the simulator with the model description language. As with channels, each point process has its own set of properties. Below are the IClamp and AlphaSynapse point processes' properties (we will only be using these two in the tutorials).

IClamp:

AlphaSynapse:
In our model, we want to stimulate the soma by giving it a current pulse. We can accomplish this by adding a IClamp as above and then setting its properties. Point processes (and other objects) differ from sections in that there is no concept of a currently accessed point process. Thus, we cannot set the properties in all the same ways we set them in sections. Rather, we must use the dot notation. So, with the IClamp now our program looks like:

create soma
access soma

nseg = 1
diam = 100
L = 100

insert hh

objectvar stim
stim = new IClamp(0.5)

stim.del = 0
stim.dur = 0.1
stim.amp = 30

Running a simulation

To ease the process of running simulations, NEURON has a standard run library of useful functions. These library functions are used to initialize the simulator, begin and end simulations, and plot variables vs. time or space during a simulation run. The most useful of these functions is the run() function. It initializes and runs a simulation.

At the oc> prompt, enter run() to run the simulation. After the simulation completes, NEURON returns you to the oc> prompt. Our program does not generate any output, so nothing will be printed, but if you print the voltage in the soma you will see that it changed from -65 mV to -76.135654 mV. To print the soma's voltage, enter:

print soma.v
or just:

print v
since soma is the most recently accessed section. This is the value at the end of the simulation time. As the default, simulations run for 5 ms of simulated time, but this can be changed by setting the tstop variable to another value (in ms). For example, to run a simulation for 1 ms, enter:

tstop = 1
run()
This will set the simulation stop time to 1 ms and run the simulation from the beginning. You can now print the soma's voltage to see what it is at that time. Try it for several different stop times (0.5, 1, 2, 4 and 10 ms).

Saving commands in a file

All of the commands in these tutorials can be entered directly from the keyboard, but this would entail quite a bit of typing, so a more practical approach is to enter the commands into a file using your favorite editor and save them. The file should start with the line:
xopen("$(NEURONHOME)/lib/hoc/noload.hoc")
to ensure that all the standard library functions are loaded. Its name should also have the extension ".hoc".

Your program can then be run by double-clicking on its icon in a Windows file manager window (note that the file must have a ".hoc" extension and have a name of 8 characters or less in length for this to work - the folders in which the file lives are also bound by this naming restriction).

A file containing all the commands you have entered so far plus some further ones is prog1.hoc. Click on this link to open this file in NEURON, or to save a copy of it for yourself (this is recommended and necessary for the following tutorials). Note that when you run this file directly you do not get any windows apart from the terminal window, but all the commands have been loaded and executed so that you can run the simulation as described below.

Programming Style

Previously we repeatedly entered the following three commands:

tstop = value
run()
print v
This results in a tremendous amount of typing, so it would be nice if we could define our own procedure to perform these commands for us.

In NEURON, you can define procedures with the proc statement. It contains three parts: the proc keyword, the name of the procedure you want to define, and the statements you want to be in the procedure. For example:

proc rununtil() {
    tstop = $1
    run()
    print "V = ", soma.v, "mV"
}
This defines a new procedure, named rununtil, which will run our simulation until a certain value and then print the soma's voltage. The parenthesis after the name are required--they tell NEURON that this is a procedure name and not a variable. Arguments can be passed to this function, and they are accessed via the $# variable where # is the number of the argument. In this case, tstop is assigned the value of the first parameter passed to the rununtil procedure.

This procedure is already in prog1.hoc so now you can display the soma's voltages at different times by simply entering:

rununtil(value)

where value is the number of milliseconds to run the simulation.

Organizing the simulation into procedures and functions is highly recommended. It leads to much clearer, more easily maintained and easier to debug simulations. For more information on procedures and functions, see the manuals and help documents. A full description of the HOC language that you have been using is given here.

In the example code provided in prog1.hoc, you will notice that there are comments throughout the code. In the example programs, these are delimited by /* at the beginning of the comment and */ at the end of the comment. Another way to delimit comments is to place // at the beginning of the comment line which makes the rest of the line a comment (i.e., the end of the comment is delimited by the end of the line). Placing comments throughout your code will help you and others understand your code, and are highly recommended.

What's next

In the next tutorial we will look at the graphical user interface and how to add graphs to display simulation intermediate and final results.


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

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