GeNN  2.2.3
GPU enhanced Neuronal Networks (GeNN)
Tutorial 1

In this tutorial we will go through step by step instructions how to create and run a GeNN simulation starting from scratch. Normally, we recommend users to use one of the example projects as a starting point but it can be very instructive to go through the necessary steps one by one once to appreciate what parts make a GeNN simulation.

The Model Definition

In this tutorial we will use a pre-defined neuron model type (TRAUBMILES) and create a simulation of ten Hodgkin-Huxley neurons [5] without any synaptic connections. We will run this simulation on a GPU and save the results to stdout.

The first step is to write a model definition function in a model definition file. Create a new empty file tenHHModel.cc with your favourite editor, e.g.

>> emacs tenHHModel.cc &
Note
The ">>" in the example code snippets refers to a shell prompt in a unix shell, do not enter them as part of your shell commands.

The model definition file contains the definition of the network model we want to simulate. First, we need to include the GeNN model specification code modelSpec.h. Then the model definition takes the form of a function named modelDefinition that takes one argument, passed by reference, of type NNmodel. Type in your tenHHModel.cc file:

// Model definintion file tenHHModel.cc
#include "modelSpec.h"
{
// definition of tenHHModel
}

Now we need to fill the actual model definition. Three standard elements to the `modelDefinition function are initialising GeNN, setting the simulation step size and setting the name of the model:

model.setDT(0.1);
model.setName("tenHHModel");
Note
With this we have fixed the integration time step to 0.1 in the usual time units. The typical units in GeNN are ms, mV, nF, and \form#10S. Therefore, this defines DT= 0.1 ms. The name of the model given in the setName method does not need to match the file name of the model definition file. However, we strongly recommend it and if conflicting, the file name of the model definition file will prevail.

Making the actual model definition makes use of the addNeuronPopulation and 'addSynapsePopulationmember functions of the NNmodel object. The arguments to a call toaddNeuronPopulations are

  • string name: the name of the population
  • int N: The number of neurons in the population
  • int type: The type of neurons in the population
  • double *p: An array of parameter values for teh neurons in the population
  • double *ini: An array of initial values for neuron variables

We first create the parameter and initial variable arrays,

// definition of tenHHModel
double p[7]= {
7.15, // 0 - gNa: Na conductance in muS
50.0, // 1 - ENa: Na equi potential in mV
1.43, // 2 - gK: K conductance in muS
-95.0, // 3 - EK: K equi potential in mV
0.02672, // 4 - gl: leak conductance in muS
-63.563, // 5 - El: leak equi potential in mV
0.143 // 6 - Cmem: membr. capacity density in nF
};
double ini[4]= {
-60.0, // 0 - membrane potential V
0.0529324, // 1 - prob. for Na channel activation m
0.3176767, // 2 - prob. for not Na channel blocking h
0.5961207 // 3 - prob. for K channel activation n
};
Note
The comments are obviously only for clarity, they can in principle be omitted. To avoid any confusion about the meaning of parameters and variables, however, we recommend strongly to always include comments of this type.

Having defined the parameter values and initial values we can now create the neuron population,

model.addNeuronPopulation("Pop1", 10, TRAUBMILES, p, ini);
Note
TRAUBMILES is a variable defined in the GeNN model specification that contains the index number of the pre-defined Traub & Miles model [5].

The model definition then needs to end on calling

model.finalize();

This completes the model definition in this example. The complete tenHHModel.cc file now should look like this:

// Model definintion file tenHHModel.cc
#include "modelSpec.h"
{
// definition of tenHHModel
model.setDT(0.1);
model.setName("tenHHModel");
double p[7]= {
7.15, // 0 - gNa: Na conductance in muS
50.0, // 1 - ENa: Na equi potential in mV
1.43, // 2 - gK: K conductance in muS
-95.0, // 3 - EK: K equi potential in mV
0.02672, // 4 - gl: leak conductance in muS
-63.563, // 5 - El: leak equi potential in mV
0.143 // 6 - Cmem: membr. capacity density in nF
};
double ini[4]= {
-60.0, // 0 - membrane potential V
0.0529324, // 1 - prob. for Na channel activation m
0.3176767, // 2 - prob. for not Na channel blocking h
0.5961207 // 3 - prob. for K channel activation n
};
model.addNeuronPopulation("Pop1", 10, TRAUBMILES, p, ini);
model.finalize();
}

This model definition suffices to generate code for simulating the ten Hodgkin-Huxley neurons on the a GPU or CPU. The second part of a GeNN simulation is the user code that sets up the simulation, does the data handling for input and output and generally defines the numerical experiment to be run.

User Code

For the purposes of this tutorial we will initially simply run the model for one simulated second and record the final neuron variables into a file. GeNN provides the code for simulating the model in a function called stepTimeCPU() (execution on CPU only) or stepTimeGPU() (execution on a GPU). To make use of this code, we need to define a minimal C/C++ main function. Open a new empty file tenHHSimulation.cc in an editor and type

// tenHHModel simulation code
#include "tenHHModel.cc"
#include "tenHHModel_CODE/definitions.h"
int main()
{
allocateMem();
initialize();
return 0;
}

This boiler plate code includes the relevant model definition file we completed earlier and the header file of entry point to the generated code definitions.h in the subdirectory tenHHModel_CODE where GeNN deposits all generated code.

Calling allocateMem() allocates the memory structures for all neuron variables and initialize() sets the initial values and copies values to the GPU.

Now we can use the generated code to execute the integration of the neuron equations provided by GeNN. To do so, we add after initialize();

stepTimeGPU(1000.0);

and we need to copy the result, and output it to stdout,

pullPop1fromDevice();
for (int i= 0; i < 10; i++) {
cout << VPop1[i] << " ";
cout << mPop1[i] << " ";
cout << hPop1[i] << " ";
cout << nPop1[i] << endl;
}

pullPop1fromDevice() copies all relevant state variables of the Pop1 neuron group from the GPU to the CPU main memory. Then we can output the results to stdout by looping through all 10 neurons and outputting the state variables VPop1, mPop1, hPop1, nPop1.

Note
The naming convention for variables in GeNN is the variable name defined by the neuron type, here TRAUBMILES defining V, m, h, and n, followed by the population name, here Pop1.

This completes the user code. The complete tenHHSimulation.cu file should now look like

// tenHHModel simulation code
#include "tenHHModel.cc"
#include "tenHHModel_CODE/definitions.h"
int main()
{
allocateMem();
initialize();
stepTimeGPU(1000.0);
pullPop1fromDevice();
for (int i= 0; i < 10; i++) {
cout << VPop1[i] << " ";
cout << mPop1[i] << " ";
cout << hPop1[i] << " ";
cout << nPop1[i] << endl;
}
return 0;
}

Makefile

A GeNN simulation is built with a simple Makefile. On Unix systems we typically name it GNUmakefile. Create this file and enter

EXECUTABLE :=tenHHSimulation
SOURCES :=tenHHSimulation.cu
include $(GENN_PATH)/userproject/include/makefile_common_gnu.mk

This defines that the final executable of this simulation is named tenHHSimulation and the simulation code is given in the file tenHHSimulation.cu that we completed above.

Now we are ready to compile and run the simulation

Making and Running the Simulation

To build the model and generate the GeNN code, type in a terminal where you are in the directory containing your tenHHModel.cc file,

>> genn-buildmodel.sh tenHHModel.cc

If your environment variables GENN_PATH and CUDA_PATH are correctly configured, you should see some compile output ending in Model build complete .... Now type

make

This should compile your tenHHSimulation executable and you can execute it with

./tenHHSimulation

The output you obtain should look like

-63.7838 0.0350042 0.336314 0.563243
-63.7838 0.0350042 0.336314 0.563243
-63.7838 0.0350042 0.336314 0.563243
-63.7838 0.0350042 0.336314 0.563243
-63.7838 0.0350042 0.336314 0.563243
-63.7838 0.0350042 0.336314 0.563243
-63.7838 0.0350042 0.336314 0.563243
-63.7838 0.0350042 0.336314 0.563243
-63.7838 0.0350042 0.336314 0.563243
-63.7838 0.0350042 0.336314 0.563243

This completes this tutorial. You have created a GeNN model and simulated it successfully!

Adding External Input

In the example we have created so far, the neurons are not connected and do not receive input. As the TRAUBMILES model is silent in such conditions, the ten neurons simply will simply rest at their resting potential. To make things more interesting, let us add a constant input to all neurons, add to the end of the modelDefinition function

model.activateDirectInput("Pop1", CONSTINP);
model.setConstInp("Pop1", 0.1);

This will add a constant input of 0.1 nA to all ten neurons. When run with this addition you should observe the output

-63.1468 0.0211871 0.987233 0.0423695
-63.1468 0.0211871 0.987233 0.0423695
-63.1468 0.0211871 0.987233 0.0423695
-63.1468 0.0211871 0.987233 0.0423695
-63.1468 0.0211871 0.987233 0.0423695
-63.1468 0.0211871 0.987233 0.0423695
-63.1468 0.0211871 0.987233 0.0423695
-63.1468 0.0211871 0.987233 0.0423695
-63.1468 0.0211871 0.987233 0.0423695
-63.1468 0.0211871 0.987233 0.0423695

This is still not particularly interesting as we are just observing the final value of the membrane potentials. To see what is going on in the meantime, we need to copy intermediate values from the device and best save them into a file. This can be done in many ways but one sensible way of doing this is to replace the line

stepTimeGPU(1000.0);

in tenHHSimulation.cu to something like this:

ofstream os("tenHH_output.V.dat");
double t= 0.0;
for (int i= 0; i < 5000; i++) {
stepTimeGPU(0.2);
pullPop1fromDevice();
os << t << " ";
for (int j= 0; j < 10; j++) {
os << VPop1[j] << " ";
}
os << endl;
t+= 0.2;
}
os.close();

After building, making and executing,

genn-builmodel.sh tenHHModel.cc
make clean all
./tenHHSimulation

there should be a file tenHH_output.V.dat in the same directory. If you plot column one (time) against column two (voltage of neuron 0), you should observe dynamics like this:

tenHHexample.png

The completed files from this tutorial can be found in userproject/tenHH_project.

Previous | Top | Next