How Brian2GeNN works inside¶
The Brian2GeNN interface is providing middleware to use the GeNN
simulator framework as a backend to the Brian 2 simulator. It has been
designed in a way that makes maximal use of the existing Brian 2 code
base by deriving large parts of the generated code from the
cpp_standalone
device of Brian 2.
Model and user code in GeNN¶
In GeNN a simulation is assembled from two main sources of code. Users of GeNN provide “code snippets” as C++ strings that define neuron and synapse models. These are then assembled into neuronal networks in a model definition function. Based on the mdoel definition, GeNN generates GPU and equivalent CPU simulation code for the described network. This is the first source of code.
The actual simulation and handling input and output data is the responsibility of the user in GeNN. Users provide their own C/C++ code for this that utilizes the generated code described above for the core simulation but is otherwise fully independent of the core GeNN system.
In the Brian2GeNN both the model definition and the user code for the
main simulation are derived from the Brian 2 model description. The
user side code for data handling etc derives more or less directly
from the Brian 2 cpp_standalone
device in the form of
GennUserCodeObjects
. The model definition code and
“code snippets” derive from separate templates and are capsulated into
GeNNCodeObjects
.
Code generation pipeline in Brian2GeNN¶
The model generation pipeline in Brian2GeNN involves a number of
steps. First, Brian 2 performs the usual interpretation of equations
and unit checking, as well as, applying an integration scheme onto
ODEs. The resulting abstract code is then translated into C++ code for
GeNNUserCodeObjects
and C++-like code for GeNNCodeObjects
. These
are then assembled using templating in Jinja2 into C++ code and GeNN
model definition code. The details of making Brian 2’s cpp_standalone
code suitable for the GeNN user code and GeNN model definition code
and code snippets are taken care of in the GeNNDevice.build
function.
Once all the sources have been generated, the resulting GeNN project is built with the GeNN code generation pipeline. See the GeNN manual for more details on this process.
Templates in Brian2GeNN¶
The templates used for code generation in Brian2GeNN, as mentioned
above, partially derive from the cpp_standalone
templates of
Brian 2. More than half of the templates are identical. Other
templates, however, in particular for the model definition file and
the main simulation engine and main entry file “runner.cc” have been
specifically written for Brian2GeNN to produce a valid GeNN project.
Data transfers and results¶
In Brian 2, data structures for initial values and synaptic
connectivities etc are written to disk into binary files if a
standalone device is used. The executable of the standalone device
then reads the data from disk and initializes its variables with it.
In Brian2GeNN the same mechanism is used, and after the data has been
read from disk with the native cpp_standalone
methods, there is a
translation step, where Brian2GeNN provides code that translates the
data from cpp_standalone
arrays into the appropriate GeNN data
structures. The methods for this process are provided in the static
(not code-generated) “b2glib”.
At the end of a simulation, the inverse process takes place and GeNN
data is transfered back into cpp_standalone
arrays. Native Brian 2
cpp_standalone
code is then invoked to write data back to disk.
If monitors are used, the translation occurs at every instance when monitors are updated.
Memory usage¶
Related to the implementation of data flows in Brian2GeNN described
above the host memory used in a run in brian2GeNN is about twice what
would have been used in a Brian 2 native cpp_standalone
implementation because all data is held in two different formats - as
cpp_standalone
arrays and as GeNN data structures.