Selecting Python, C++ or GPU device¶
The device is selected in the model and network configuration file. Set the “device” to either
GeNN (case insensitive).
Cpp (C++) device is a safe bet for most applications.
Python skips compilation, and may be best for minor systems or when devices run into
GeNN may be beneficial for long non-array runs.
How the CxSystem works¶
The CxSystem starts by calling the main object
cxsystem() in python interpreter. The configuration files are set either in the BUI, as command-line
arguments for cxsystem2 command or python interpreter after cxsystem() call, or at the end of cxsystem.py file.
One of the strengths of the CxSystem is the ability to dynamically compile the model. This bypasses the traditional way of hard coding much of the model which would limit flexibility. This flexibility comes with some added complexity in the way the CxSystem builds the devices.
The implemented system employs the Brian2GeNN python module to generate GeNN (GPU enhanced Neuronal Network simulation environment) code for eventually running the Brian2 codes on GeNN. Note that using the GeNN device, CxSystem (via GeNN) only employs one of the GPUs in the system and therefore cannot be used in cluster. In order to understand how this system works, one should initially understand how Brian2GeNN limits Brian2. Most of the exclusions are presented in Brian2GeNN documentation. Perhaps the most effective limitation is lack of support for using Multiple networks in Brian2, i.e. only the magic network can be used. Using the magic network, only the “visible” objects, that are explicitly defined in the code will be collected. In other words, any Brian2 object that is created in a custom class, will not be collected and will eventually raise an error. We have used two solutions to address this issue, Syntax Bank and Global variables:
Creating a Syntax Bank¶
In this method, a syntax string is built for all Brian2 internal objects. These syntaxes are then run after the main object call. Suppose the cortical system object is named CX and a
NeuronGroup() object called
NG is created in a method inside the
NG = NeuronGroup(1, eqs)
NG will not be collected for magic network as it is inside a method of
CX. However, we can anticipate a syntax for this neuron group and save it in a syntax bank attribute in
syn1 = "NG = NeuronGroup(1, eqs)" CX.syntax_bank = append(CX.syntax_bank, syn1)
All of the elements of this
CX.syntax_bank* can then be iterated and run using the dynamic compiler, i.e.
exec command. Note that all the sub objects of a syntax should be saved in syntax_bank as well. For instance, the last example will raise an error since
eqs is not defined. Hence, before running the
syn1, one should initially run the syntax for
This method has a fundamental limitation: first, the syntax bank should run in a hierarchical manner. In previous example, the syntax for
eqs should be run before
NeuronGroup() syntaxes should be run before
synapses.connect() should be run after
Synapses(). This process was manually coded into the main file for running the codes in a hierarchical manner, which we consider an untidy solution.
The syntax bank approach call for prefixes for object names. For instance, all of the
NeuronGroup() have a prefix of
For each neuron group, similar prefixes are also needed for variables such as:
- Number of neurons in each group:
- Threshold value:
- Reset value:
- Refraction value:
Several prefixes are also demanded for
- Synaptic object:
- Synaptic equation:
- Pre Synaptic group equation:
- Post Synaptic group equation:
And similar prefixes for monitors:
- Spike Monitors:
- State Monitors:
Although mentioned as a dangerous method in the literature, updating the
Globals() directly, is a practical approach in our case. This method uses aforementioned prefixes and corresponding variables. However, there is no need for the newly generated variables to wait in the syntax bank so to be run after
They can be implicitly executed while CxSystem is running and still magic network of Brian2 would be able to access them since they are in
Globals(). Thus, the user does not have to face a manual syntax-executer outside of the main object call.
Accordingly, most of the
exec commands inside the main object
CxSystem() are creating the required variables and making them visible to magic network of Brian2 by updating the
Globals(). In the following example, the
NG0 is put into the
Fig.1 illustrates the schematic of the cortical system internal component: