GeNN  2.2.3
GPU enhanced Neuronal Networks (GeNN)
Tutorial 2

In this tutorial we will learn to add synapsePopulations to connect neurons in neuron groups to each other with synatic models. As an example we will connect the ten Hodgkin-Huxley neurons from tutorial 1 in a ring of excitatory synapses.

First, copy the files from Tutorial 1 into a new directory and rename them to new names, e.g.

>> cp -r tenHH_project tenHHRing_project
>> cd tenHHRing_project
>> mv tenHHModel.cc tenHHRingModel.cc
>> mv tenHHSimulation.cu tenHHRingSimulation.cu

Now, we need to add a synapse group to the model that allows to connect neurons from the Pop1 group to connect to other neurons of this group. Open tenHHRingModel.cc, change the model name inside,

model.setName("tenHHRing");

Adding Synaptic connections

Now we need additional initial values and parameters for the synapse and post-synaptic models. We will use the standard NSYNAPSE weightupdate model and EXPDECAY post-synaptic model. They need intial variables and parameters as follows:

double s_ini[1] = {
0.0 // 0 - g: the synaptic conductance value
};
double *s_p= NULL;
double *ps_ini= NULL;
double ps_p[2]= {
1.0, // 0 - tau_S: decay time constant for S [ms]
-80.0 // 1 - Erev: Reversal potential
};

If an array is not needed we set it to the NULL pointer. Here there are for example no synaptic parameters and no initial values for the post-synaptic mechanism. We can then add a synapse population at the end of the modelDefinition(...) function,

model.addSynapsePopulation("Pop1self", NSYNAPSE, DENSE, INDIVIDUALG, NO_DELAY, EXPDECAY, "Pop1", "Pop1", s_ini, s_p, ps_ini, ps_p);

The addSynapsePopulation parameters are

  • const char *name: The name of the synapse population, here "Pop1self"
  • int sType: The type of synapse to be added, we here use the predefined typse NSYNAPSE. See Built-in Models for all available predefined synapse types.
  • int sConn: The type of synaptic connectivity, here DENSE which means we will provide a full connectivity mtrix later.
  • int gType: The way how the synaptic conductivity g will be defined. With GLOBALG we indicate that all conductance are of the same conductance value, which will be the value given in sPara.
  • int delay: NO_DELAY means that there wil be no delays for synaptic signal propagation.
  • int postSyn: Postsynaptic integration method, we are here using the standard model of an exponential decay of synaptic excitation.
  • char *preName: Name of the pre-synaptic neuron population, here the Pop1 population.
  • char *postName: Name of the post-synaptic neuron population, here also Pop1.
  • double *sIni: A C-array of doubles containing initial values for the synaptic variables.
  • double *sParam: A C-array of double precision that contains parameter values (common to all synapses of the population)
  • double *psIni: A C-array of double precision numbers containing initial values for the post-synaptic model variables
  • double *psPara: A C-array of double precision numbers containing parameters fo the post-snaptic model.

Adding the addSynapsePopulation command to the model definition informs GeNN that there will be synapses between the named neuron populations, here between population Pop1 and itself. The detailed connectivity as defined by the variables g, we have still to define in the setup of our simulation. As always, the modelDefinition function ends on

model.finalize();

At this point our model definition file tenHHRingModel.cc should look like this

// Model definintion file tenHHModel.cc
#include "modelSpec.h"
{
// definition of tenHHModel
model.setDT(0.1);
model.setName("tenHHRingModel");
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.activateDirectInput("Pop1", CONSTINP);
model.setConstInp("Pop1", 0.1);
double s_ini[1] = {
0.0 // 0 - g: the synaptic conductance value
};
double *s_p= NULL;
double *ps_ini= NULL;
double ps_p[2]= {
1.0, // 0 - tau_S: decay time constant for S [ms]
-80.0 // 1 - Erev: Reversal potential
};
model.addSynapsePopulation("Pop1self", NSYNAPSE, DENSE, INDIVIDUALG, NO_DELAY, EXPDECAY, "Pop1", "Pop1", s_ini, s_p, ps_ini, ps_p);
model.finalize();
}

Defining the Detailed Synaptic Connections

Open the tenHHRingSimulation.cu file and update the file names of includes:

// tenHHRingModel simulation code
#include "tenHHRingModel.cc"
#include "tenHHRingModel_CODE/definitions.h"

Now we need to add code to generate the desired ring connectivity.

allocateMem();
initialize();
// define the connectivity
int pre, post;
for (int i= 0; i < 10; i++) {
pre= i;
post= (i+1)%10;
gPop1self[pre*10+post]= 0.01;
}
pushPop1selftoDevice();

After memory allocation and initialization gPop1self will contain only zeros. We then assign in the loop a non-zero conductivity of 0.01 $\mu$S to all synapses from neuron i to i+1 (and 9 to 0 to close the ring).

After adjusting the GNUmakefile to read

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

we can build the model

>> genn-buildmodel.sh tenHHRingModel.cc

and make it

>> make clean all

After this there should be an exectable tenHHRingSimulation, which can be executed,

>> ./tenHHRingSimulation

which should again result in

-64.9054 0.0147837 0.981337 0.030886
-64.9054 0.0147837 0.981337 0.030886
-64.9054 0.0147837 0.981337 0.030886
-64.9054 0.0147837 0.981337 0.030886
-64.9054 0.0147837 0.981337 0.030886
-64.9054 0.0147837 0.981337 0.030886
-64.9054 0.0147837 0.981337 0.030886
-64.9054 0.0147837 0.981337 0.030886
-64.9054 0.0147837 0.981337 0.030886
-64.9054 0.0147837 0.981337 0.030886

If we plot the content of columns one and two of tenHHexample.V.dat it looks very similar as in Tutorial 1

tenHHRingexample1.png

This is because the inhibitory synapses we created were all triggered at the same time so that they act during a post-synaptic spike which makes their effect all but invisible.

Setting Heterogeneous Initial Conditions

If we define different initial conditions for each of the ten neurons, i.e. add after initialize(),

// set initial variables
for (int i= 0; i < 10; i++) {
VPop1[i]= -60.0+i;
}
pushPop1toDevice();

then we observe different final values for each neuron,

-57.3412 0.06223 0.981374 0.104417
-53.3189 0.442962 0.0664687 0.764513
-73.1413 0.00253709 0.927251 0.0277236
-67.1179 0.00927304 0.986692 0.0206106
-63.5878 0.01938 0.991071 0.0387962
-62.2114 0.0255295 0.990933 0.0504799
-61.404 0.0298902 0.990949 0.0586459
-60.6691 0.034405 0.990225 0.0668015
-59.8977 0.0397467 0.988701 0.0758159
-58.9727 0.0470178 0.98615 0.0866963

and zooming in on the first 200 ms, the voltage of the first neuron now looks like this

tenHHRingexample2.png

The complete codes for this tutorial are in userproject\tenHHRing_project.

Previous | Top | Next