Neurons and Connections


Importing PyNN

The simulator used by a PyNN script is determined by which module is imported from the PyNN package, e.g.:

>>> from pyNN.neuron import *
>>> from pyNN.nest import *
>>> from pyNN.pcsim import *
>>> from pyNN.brian import *

After this line, all PyNN code is independent of the simulator used, although it is possible to include simulator-specific code in the script as well (if simulator-independence is not important to you, or if you are in the process of porting simulator-specific code to pure PyNN code).

Initialising the simulator

Before using any other functions or classes from PyNN, the user must call the setup() function:

>>> setup()

setup() takes various optional arguments: setting the simulation timestep (there is currently no support in the API for variable timestep methods although native simulator code can be used to select this option where the simulator supports it) and setting the minimum and maximum synaptic delays, e.g.:

>>> setup(timestep=0.1, min_delay=0.1, max_delay=0.5)

In previous versions, setup() took a debug argument for configuring logging. To allow more flexibility, configuration of logging must now be done separately. There is a convenience function in the pyNN.utility module to simplify this:

>>> from pyNN.utility import init_logging
>>> init_logging("logfile", debug=True)

or you can configure the Python logging module directly.

Creating neurons

Neurons are created with the create() function. To create a single integrate-and-fire neuron, type:

>>> create(IF_curr_alpha)

Here, IF_curr_alpha is a particular class of IF neuron with alpha-function shaped synaptic currents, that will work with any PyNN simulation engine, whether NEURON, NEST, PCSIM or Brian. IF_curr_alpha is a so-called 'standard cell', implemented as a Python class. For more information, see the section StandardCells.

You don't have to use standard cells. You can also use any neuron model that is available in an individual simulator, although of course your simulation will then only run with that simulator, for example:

>>> create('iaf_neuron')

iaf_neuron is a neuron model available in the NEST simulator.

To create many neurons at once, add the n argument, e.g.:

>>> create(IF_curr_alpha, n=10)

The neurons we have created so far have all had default parameter values, stored in the default_values of the standard cell class, e.g.:

>>> IF_curr_alpha.default_parameters
{'tau_refrac': 0.0, 'tau_m': 20.0, 'i_offset': 0.0, 'cm': 1.0, 'v_init': -65.0,
 'v_thresh': -50.0, 'tau_syn_E': 0.5, 'v_rest': -65.0, 'tau_syn_I': 0.5,
 'v_reset': -65.0}

To use different parameter values, use the cellparams argument, e.g.:

>>> create(IF_curr_alpha, cellparams={'tau_m': 15.0, 'cm': 0.9}, n=10)

If you try to set a non-existent parameter, or pass an invalid value, PyNN will raise an Exception, e.g.:

>>> create(IF_curr_alpha, cellparams={'foo': 15.0})
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "/usr/lib/python/site-packages/pyNN/common.py", line 655, in create
    all_cells, mask_local, first_id, last_id = simulator.create_cells(cellclass, cellparams, n)
  File "/home/andrew/dev/pyNN/neuron/simulator.py", line 287, in create_cells
    celltype = cellclass(cellparams)
  File "/usr/lib/python/site-packages/pyNN/neuron/cells.py", line 442, in __init__
    cells.IF_curr_alpha.__init__(self, parameters) # checks supplied parameters and adds default
  File "/usr/lib/python/site-packages/pyNN/common.py", line 460, in __init__
    self.parameters = self.__class__.checkParameters(parameters, with_defaults=True)
  File "/usr/lib/python/site-packages/pyNN/common.py", line 504, in checkParameters
    raise NonExistentParameterError(k, cls)
NonExistentParameterError: foo (valid parameters for IF_curr_alpha are: cm, i_offset, tau_m, tau_refrac, tau_syn_E, tau_syn_I, v_init, v_reset, v_rest, v_thresh)
>>> create(IF_curr_alpha, cellparams={'tau_m': 'bar'})
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
    create(IF_curr_alpha, cellparams={'tau_m': 'bar'})
  File "/usr/lib/python/site-packages/pyNN/common.py", line 655, in create
    all_cells, mask_local, first_id, last_id = simulator.create_cells(cellclass, cellparams, n)
  File "/usr/lib/python/site-packages/pyNN/neuron/simulator.py", line 287, in create_cells
    celltype = cellclass(cellparams)
  File "/usr/lib/python/site-packages/pyNN/neuron/cells.py", line 442, in __init__
    cells.IF_curr_alpha.__init__(self, parameters) # checks supplied parameters and adds default
  File "/usr/lib/python/site-packages/pyNN/common.py", line 460, in __init__
    self.parameters = self.__class__.checkParameters(parameters, with_defaults=True)
  File "/usr/lib/python/site-packages/pyNN/common.py", line 494, in checkParameters
    raise InvalidParameterValueError(err_msg)
InvalidParameterValueError: For tau_m in IF_curr_alpha, expected <type 'float'>, got <type 'str'> (bar)

If you wish to do something with the cell after creating it: record from it, change a parameter, connect it to another cell, you should assign the return value of the function to a variable, e.g.:

>>> cell = create(IF_curr_alpha)
>>> cell_list = create(IF_curr_alpha, n=10)

The create() function returns either a cell id object or a list of id objects.

Connecting neurons

Any neuron that emits spikes can be connected to any neuron with at least one synapse using the connect() function, e.g.:

>>> spike_source = create(SpikeSourceArray, cellparams={'spike_times': [10.0, 20.0, 30.0]})
>>> cell_list2 = create(IF_curr_exp, n=10)
>>> connect(spike_source, cell_list2)

In this case we connect a spike-generating mechanism (SpikeSourceArray is a 'standard cell' model that emits spikes at times specified by the spike_times parameter) to each cell in the list cells, i.e. we create 10 connections at once. For clarity, we could also have specified the argument names:

>>> connect(source=spike_source, target=cell_list2)

Either source or target or both may be individual cell ids or lists of ids. In the latter case, each source (presynaptic) cell is connected to every target (postsynaptic) cell with probability given by the optional argument p, which defaults to 1, e.g.:

>>> source_list = cell_list
>>> target_list = cell_list2
>>> connect(source_list, target_list, p=0.5)

When specifying connections as above, default values are given to the synaptic weight and delay. These values are seldom very useful, and it is better to specify the weight and delay arguments of connect(), e.g.:

>>> connect(source_list, target_list, weight=1.5, delay=0.5)

Weights are specified in nA for 'current-based' synapses or µS for 'conductance-based' synapses. Delays are in ms. For current-based synapses, weights should be negative for inhibitory synapses. For conductance-based synapses, weights should always be positive, since the effect of a synapse is determined by its reversal potential.

If the neuron model has more than one synapse mechanism, or more than one synaptic location, the particular synapse to which the connection should be made is specified with the synapse_type argument, e.g.:

>>> connect(source_list, target_list, weight=-1.5, delay=0.5, synapse_type='inhibitory')

(the attribute synapse_types of all standard cell objects contains a list of the synapse types for that cell type).

Setting neuron parameters

There are many ways to change the parameters for individual neurons and post-synaptic mechanisms after creation of the neuron. To change a single parameter of a single neuron, just set the relevant attribute of the neuron ID object, e.g.:

>>> cells = create(IF_curr_exp, cellparams={'v_init': -70.0}, n=10)
>>> cells[0].tau_m
20.0
>>> cells[0].tau_m = 15
>>> cells[0].tau_m
15.0

To change several parameters at once for a single neuron, use the set_parameters() method of the neuron ID, e.g.:

>>> cells[1].set_parameters(tau_m=10.0, cm=0.5)
>>> cells[1].tau_m
10.0
>>> cells[1].cm
0.5

To change parameters for several cells at once, use the set() function, e.g.:

>>> set(cells[0:5], param='v_init', val=-65.0)
>>> print cells[0].v_init
-65.0
>>> print cells[5].v_init
-70.0

Individual parameters can be set using the param and val arguments, as above, or multiple parameters can be set at once by passing a dictionary of name:value pairs as the param argument, with val empty, e.g.:

>>> set(cells, param={'tau_refrac': 2.0, 'tau_syn_E': 5.0})

Setting position in space

In some cases it is important to know the position of a neuron in space. This information can be set and retrieved using the position attribute of the neuron ID:

>>> cells[0].position = (75, 456, 56)
>>> cells[0].position
array([ 75, 456, 56])

Positions must always be in 3D, and may be given as integers or floating-point values, and as tuples or as numpy arrays. No specific coordinate system or scale of units is assumed, although many parts of PyNN do assume a Euclidean coordinate system.

Injecting current

Most standard cells have an i_offset parameter, which allows a constant current to be injected into a neuron. If you want to have a time varying current, you may create a CurrentSource object and connect it to the neuron either using the inject() method of the neuron ID or using the inject_into() method of the CurrentSource:

>>> pulse = DCSource(amplitude=0.5, start=20.0, stop=80.0)
>>> steps = StepCurrentSource(times=[0.0, 50.0, 100.0], amplitudes=[0.1, 0.2, 0.3])
>>> pulse.inject_into(cells[3:7])
>>> cells[9].inject(steps)

Recording spikes and membrane potential

To record action potentials use the record() function, to record membrane potential use the record_v() function and to record synaptic conductances use the record_gsyn() function. The arguments for all three functions are a cell id or list of ids, and a filename, e.g.:

>>> record(cell, "spikes.dat")
>>> record_v(cell_list, "Vm.dat")

By default, all simulators write data files in the same format.

The beginning of a typical spike file looks like:

# dt = 0.1
# n = 1000
0.0     2
0.3     5
0.4     3
0.9     2
1.0     1
. . .

The beginning of a typical membrane potential file looks like:

# dt = 0.1
# n = 1000
-65.0   0
-64.9   0
-64.7   0
-64.5   0
. . .

Both file types begin with header lines giving the timestep (there is currently no support for variable-time step recording) and the number of data points in the file. Each line of the spike file then gives the occurence time of a spike (in ms) and the id of the neuron in which it was recorded. Each line of the membrane potential file gives the membrane potential (in mV) followed by the id of the neuron in which it was recorded. In both cases, whether the file is sorted by cell id or by time depends on the simulator: it is not standardised.

In some cases it is more efficient to write files in the simulator's native format, rather than the standard PyNN format. In this case, use the compatible_output=False argument to the end() function.

For recording to binary (e.g. HDF5) rather than text files, see the chapter on file formats.

Running a simulation

The run() function runs the simulation for a given number of milliseconds, e.g.:

>>> run(1000.0)

Repeating a simulation

If you wish to reset network time to zero to run a new simulation with the same network (with different parameter values, perhaps), use the reset() function. Note that this does not change the network structure, nor the choice of which neurons to record (from previous record() calls).

Finishing up

Just as a simulation must be begun with a call to setup(), it must be ended with a call to end().

Examples

There are several example scripts in the examples directory of the source distribution.