# The procedural API¶

The procedural API (also previously known as the “low-level” API) gives a view of a model that is centred more on individual neurons and connections, rather than on populations of neurons and projections between them. This viewpoint may be more suited for small networks, or when porting a model from a simulator that has a neuron-centred viewpoint. It should be noted, however, that this API is just a wrapper around the main, object-oriented API. For example, the create() function returns a Population object, it is just that it is then treated as a list of neurons rather than as a single object.

## Creating neurons¶

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

>>> create(IF_curr_alpha)


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

>>> cells = create(IF_curr_alpha, n=10)


Although the return value is actually a Population object, it can be treated in most ways like a list, accessing individual items:

>>> print cells[0].tau_m
20.0


or a range of items:

>>> for cell in cells[5:8]:
...     cell.cm = 0.5


or adding two lists together:

>>> more_cells = create(IF_cond_exp, n=5)
>>> all_cells = cells + more_cells
>>> some_cells = cells[5:] + more_cells[2:4]


(note that all_cells and some_cells here are Assembly objects).

## Connecting neurons¶

Lists of neurons (Populations or Assemblys) can be connected using the connect() function, e.g.:

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


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.

The connect() function behaves similarly to creating a Projection, but without the flexibility to choose the connection algorithm, or to have plastic synapses.

If the source or target is a list of cells (a Population, etc.), 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 = cells
>>> target_list = more_cells
>>> 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_thresh': -50.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_thresh', val=-55.0)
>>> print cells[0].v_thresh
-55.0
>>> print cells[5].v_thresh
-50.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})


## Injecting current¶

If you want to inject a current (which may be time varying), 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 a Population, Assembly or PopulationView), and a filename, e.g.:

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


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)


## Finishing up¶

Just as a simulation must be begun with a call to setup(), it must be ended with a call to end(). For the procedural API, this is also the point at which data gets written to file.

## Examples¶

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