This document describes how to implement a new
Device for Brian. This is a
somewhat complicated process, and you should first be familiar with devices
from the user point of view (Computational methods and efficiency) as well as the code
generation system (Code generation).
We wrote Brian’s devices system to allow for two major use cases, although it can potentially be extended beyond this. The two use cases are:
Runtime mode. In this mode, everything is managed by Python, including memory management (using numpy by default) and running the simulation. Actual computational work can be carried out in several different ways, including numpy or Cython.
Standalone mode. In this mode, running a Brian script leads to generating an entire source code project tree which can be compiled and run independently of Brian or Python.
Runtime mode is handled by
RuntimeDevice and is already implemented, so here
I will mainly discuss standalone devices. A good way to understand these
devices is to look at the implementation of
CPPStandaloneDevice (the only
one implemented in the core of Brian). In many cases, the simplest way to
implement a new standalone device would be to derive a class from
CPPStandaloneDevice and overwrite just a few methods.
Memory is managed primarily via the
Device.set_value methods. When a new array is created, the
method is called, and when trying to access this memory the other two are
RuntimeDevice uses numpy to manage the memory and returns the
underlying arrays in these methods. The
CPPStandaloneDevice just stores
a dictionary of array names but doesn’t allocate any memory. This information
is later used to generate code that will allocate the memory, etc.
As in the case of runtime code generation, computational work is done by
a collection of
CodeObject s. In
CPPStandaloneDevice, each code object
is converted into a pair of
.h files, and this is probably
a fairly typical way to do it.
Device.build is used to generate the project. This can be
implemented any way you like, although looking at
is probably a good way to get an idea of how to do it.
Device override methods¶
Several functions and methods in Brian are decorated with the
decorator. This mechanism allows a standalone device to override the behaviour
of any of these functions by implementing a method with the name provided to
device_override. For example, the
CPPStandaloneDevice uses this to
There are some other methods to implement, including initialising arrays, creating spike queues for synaptic propagation. Take a look at the source code for these.