Record from simulations¶
Recording devices (or recorders, in short) are used to sample or collect observable quantities like potentials, conductances, or spikes from neurons and synapses.
To determine what happens to recorded data, each recording device can
specify a recording backend in its record_to
property. The
default backend is memory, which stores the recorded data in memory
for later retrieval. Other backends write the data to file, to the
screen, or stream it to other applications via the network. The
different backends and their usage are explained in detail in the
section about Recording Backends.
Recording devices can only reliably record data that was generated during the previous simulation time step interval. See the guide about running simulations for details about the temporal aspects of the simulation loop.
Note
Due to the need for internal buffering and the unpredictable order of thread execution, events are not necessarily recorded in chronological order.
Recording devices can fundamentally be subdivided into two groups:
Collectors gather events sent to them. Neurons are connected to collectors and the collector gathers the events emitted by the neurons connected to it.
Samplers actively interrogate their targets at given time intervals. This means that the sampler must be connected to the neuron (not the neuron to the sampler), and that the neuron must support the particular type of sampling.
What values can I record?¶
This depends on neuron or synapse model specified.
You can get a list of properties that you can record using the recordables
property.
>>> nest.GetDefaults("iaf_cond_alpha")["recordables"] ["g_ex", "g_in", "t_ref_remaining", "V_m"]
Recorders available in NEST¶
Check out the following examples to see how the recorders are used:
Where does data end up?¶
After a recording device has collected or sampled data, the data is handed to a dedicated recording backend, set for each recorder. These are responsible for how the data are processed.
To specify the recording backend for a given recording device, the
property record_to
of the latter has to be set to the name of the
recording backend to be used. This can either happen already in the
call to Create()
or by using SetStatus()
on the model instance.
sr = nest.Create("spike_recorder", params={"record_to": "memory"})
Storing data in memory using the memory backend is the default for all recording devices as this does not require any additional setup of data paths or filesystem permissions and allows a convenient readout of data by the user after simulation.
For example, you can use the events
property to get the data output from the memory backend
from any of the recorders:
>>> spike_recorder.get("events")
{"senders": array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]),
"times": array([ 2.1, 4.4, 6.7, 8.9, 11.1, 13.3, 15.5, 17.7, 19.9, 22.1, 24.3, 26.5, 28.7])}
Additional properties can be set, depending on the recorder and recording backend used.
For example:
mm = nest.Create( "multimeter",
params={"interval": 0.1, "record_from": ["V_m", "g_ex", "g_in"], "record_to": "ascii", "label": "my_multimeter"},
)
Each recording backend may provide a specific set of parameters
(explained in the backend documentation below) that will be included
in the model status dictionary once the backend is set. This means
that these parameters can only be reviewed and changed after the
backend has been selected. In particular, recording-device specific
per-device parameters cannot be set using SetDefaults()
, but must
rather be supplied either in the call to Create()
or set on an
instance using SetStatus()
.
Note
Even though parameters of different recording backends may have the same name, they are separate entities internally. This means that a value that was set for a parameter of a recording device when a specific backend was selected has to be set again on the new backend, if the backend is changed later on.
The full list of available recording backends can be obtained from the
kernel attribute recording_backends
.
>>> print(nest.recording_backends)
("ascii", "memory", "mpi", "screen", "sionlib")
If a recording backend has global properties (i.e., parameters shared
by all enrolled recording devices), those can be inspected with
GetDefaults()
>>> nest.GetDefaults("sionlib")
{"buffer_size": 1024,
"filename": "",
"sion_chunksize": 262144,
"sion_collective": False,
"sion_n_files": 1}
Such global parameters can be set using SetDefaults()
>>> nest.SetDefaults("sionlib", {"buffer_size": 512})
Built-in backends¶
Following is a list of built-in recording backends that come with NEST. Please note that the availability of some of them depends on the compile-time configuration for NEST. See the backend documentation for details.
Recording backend memory - Store data in main memory¶
Description¶
When a recording device sends data to the memory
backend, it is
stored internally in efficient vectors. These vectors are made
available to the user level in the device’s status dictionary under
the key events
.
The events
dictionary always contains the global IDs of the source
nodes of the recorded data in the field sender
. It also always
contains the time of the recording. Depending on the setting of the
property time_in_steps
, this time can be stored in two different
formats:
If
time_in_steps
is false (which is the default), the time is stored as a single floating point number in the fieldtimes
, interpreted as the simulation time in msIf
time_in_steps
is true, the time is stored as a pair consisting of the integer number of simulation time steps in units of the simulation resolution intimes
and the negative offset from the next such grid point as a floating point number in ms inoffset
.
All additional data collected or sampled by the recording device is
contained in the events
dictionary in arrays. These data are named
based on the recordable they came from and with the appropriate data
type (either integer or floating point).
The number of events that were collected by the memory
backend can
be read out of the n_events entry in the status dictionary of the
recording device. To delete data from memory, n_events can be set to
0. Other values cannot be set.
Parameter summary¶
- events
A dictionary containing the recorded data in the form of one numeric array for each quantity measured. It always has the sender global IDs of recorded events under the key
senders
and the time of the recording, the format of which depends on the setting oftime_in_steps
.- n_events
The number of events collected or sampled since the last reset of n_events. By setting n_events to 0, all events recorded so far will be discarded from memory.
- time_in_steps
A Boolean (default: false) specifying whether to store time in steps, i.e., in integer multiples of the simulation resolution (under the key
times
of theevents
dictionary) plus a floating point number for the negative offset from the next grid point in ms (under keyoffset
), or just the simulation time in ms under keytimes
. This property cannot be set after Simulate has been called.
Recording backend ascii - Write data to plain text files¶
Description¶
The ascii recording backend writes collected data persistently to a plain text ASCII file. It can be used for small to medium sized simulations, where the ease of a simple data format outweighs the benefits of high-performance output operations.
This backend will open one file per recording device per thread on each MPI process. This can cause a high load on the file system in large simulations. This backend can become prohibitively inefficient, particularly on machines with distributed filesystems. In case you experience such scaling problems, the recording backend for SIONlib may be a possible alternative.
Filenames of data files are determined according to the following pattern:
data_path/data_prefix(label|model_name)-node_id-vp.file_extension
The properties data_path
and data_prefix
are global kernel
properties. They can, for example, be set during repetitive simulation
protocols to separate the data originating from individual runs. The
label
replaces the model name component if it is set to a non-empty
string. node_id
and vp
denote the zero-padded global ID and virtual
process of the recorder writing the file. The filename ends in a dot
and the file_extension
.
The life of a file starts with the call to Prepare
and ends with
the call to Cleanup
. Data that is produced during successive calls
to Run
in between a pair of Prepare
and Cleanup
calls will
be written to the same file, while the call to Run
will flush all
data to the file, so it is available for immediate inspection.
If the file name already exists when creating a new recording, the
call to Prepare
will fail with a FileExists
error. To overwrite
the old file, the kernel property overwrite_files
can be set to
True
using the corresponding kernel attribute. An alternative way
for avoiding name clashes is to set the kernel attributes
data_path
or data_prefix
, to write to a different file.
Data format¶
Any file written by the ascii recording backend starts with an informational header. The first header line contains the NEST version, with which the file was created, followed by the version of the recording backend in the second. The third line describes the data by means of the field names for the different columns. All lines of the header start with a # character.
The first field of each record written is the node ID of the neuron the event originated from, i.e., the source of the event. This is followed by the time of the measurement, the recorded floating point values and the recorded integer values.
The format of the time field depends on the value of the property
time_in_steps
. If set to false (which is the default), time is
written as a single floating point number representing the simulation
time in ms. If time_in_steps
is true, the time of the event is
written as a pair of values consisting of the integer simulation time
step in units of the simulation resolution and the negative floating
point offset in ms from the next integer grid point.
Note
The number of decimal places for all decimal numbers written can be
controlled using the recorder property precision
.
Parameter summary¶
- file_extension
A string (default: “dat”) that specifies the file name extension, without leading dot. The generic default was chosen, because the exact type of data cannot be known a priori.
- filenames
A list of the filenames where data is recorded to. This list has one entry per local thread and is a read-only property.
- label
A string (default: “”) that replaces the model name component in the filename if it is set.
- precision
An integer (default: 3) that controls the number of decimal places used to write decimal numbers to the output file.
- time_in_steps
A Boolean (default: false) specifying whether to write time in steps, i.e., in integer multiples of the simulation resolution plus a floating point number for the negative offset from the next grid point in ms, or just the simulation time in ms. This property cannot be set after Simulate has been called.
Recording backend screen - Write data to the terminal¶
Description¶
When initially conceiving and debugging simulations, it can be useful to check recordings in a more ad hoc fashion. The recording backend screen can be used to dump all recorded data onto the console for quick inspection.
The first field of each record written is the node ID of the neuron the event originated from, i.e., the source of the event. This is followed by the time of the measurement, the recorded floating point values, and the recorded integer values.
The format of the time field depends on the value of the property
time_in_steps
. If set to false (which is the default), time is
written as one floating point number representing the simulation time
in ms. If time_in_steps
is true, the time of the event is written
as a value pair consisting of the integer simulation time step and the
floating point offset in ms from the next grid point.
Note
Using this backend for production runs is not recommended, as it may produce huge amounts of console output and considerably slow down the simulation.
Parameter summary¶
- precision
controls the number of decimal places used to write decimal numbers to the terminal.
- time_in_steps
A boolean (default: false) specifying whether to print time in steps, i.e., in integer multiples of the resolution and an offset, rather than just in ms.
Recording backend sionlib - Store data to an efficient binary format¶
Description¶
Availability
This recording backend is only available if NEST was compiled with support for MPI and SIONlib.
The sionlib recording backend writes collected data persistently to a binary container file (or to a rather small set of such files). This is especially useful for large-scale simulations running in a distributed way on many MPI processes/OpenMP threads. In such usage scenarios, writing to plain text files (see recording backend for ASCII files) would cause a large overhead because of the huge number of generated files and thus be very inefficient.
The implementation of the sionlib backend is based on the SIONlib library. Depending on the I/O architecture of the compute cluster or supercomputer and the global settings of the sionlib recording backend, either a single container file or a set of these files is created. In case of a single file, it is named according to the following pattern:
<data_path>/<data_prefix><filename>
In case of multiple files, this name is extended for each file by a
dot followed by a consecutive number. The properties data_path
and
data_prefix
are global kernel properties. They can for example be
set during repetitive simulation protocols to separate the data
originating from individual runs.
The life of a set of associated container files starts with the call
to Prepare
and ends with the call to Cleanup
. Data that is
produced during successive calls to Run
in between a pair of
Prepare
and Cleanup
calls will be written to the same file
set. When creating a new recording, if the filename already exists,
the Prepare
call will fail with a corresponding error message. To
instead overwrite the old file set, the kernel property
overwrite_files
can be set to True
using the corresponding kernel
attribute. An alternative way for avoiding name clashes is to set the
kernel attributes data_path
or data_prefix
, to write to a different file.
Data format¶
In contrast to other recording backends, the sionlib
backend
writes the data from all recorders using it to a single container
file(s). The file(s) contain the data in a custom binary format, which
is composed of a series of blocks in the following order:
The body block contains the actual data records; the layout of an individual record depends on the type of the device and is described by a corresponding entry in the device info block
The file info block keeps the file’s metadata, like version information and such
The device info block stores the properties and a data layout description for each device that uses the
sionlib
backendThe tail block contains pointers to the file info block
The data layout of the NEST SIONlib file format v2 is shown in the following figure.
Reading the data¶
As the binary format of the files produced by the sionlib
does not
conform to any standard, parsing them manually might be a bit
cumbersome. To ease this task, we provide a reader module for Python
that makes the files available in a convenient way. The source code
and further documentation for this module can be found in its own
repository.
Recorder-specific parameters¶
- label
A recorder-specific string (default: “”) that serves as alias name for the recording device, and which is stored in the metadata section of the container files.
Global parameters¶
These parameters can be set by assigning a nested dictionary to the
kernel attribute recording_backends
. The dictionary has to have
the form {'sionlib': {k_1: v_1, …, k_n: v_n}
with k_i
being
from the following list:
- filename
The filename (default: “output.sion”) part of the pattern according to which the full filename (incl. path) is generated (see above).
- sion_n_files
The number of container files (default: 1) used for storing the results of a single call to
Simulate
(or of a singlePrepare
-Run
-Cleanup
cycle). The default is one file. Using multiple files may have a performance advantage on large computing clusters, depending on how the (parallel) file system is accessed from the compute nodes.- sion_chunksize
In SIONlib nomenclature, a single OpenMP thread running on a single MPI process is called a task. For each task, a specific number of bytes is allocated in the container file(s) from the beginning. This number is set by the parameter
sion_chunksize
(default: 262144). If the number of bytes written by each task during the simulation is known in advance, it is advantageous to set the chunk size to this value. In this way, the size of the container files has not to be adjusted by SIONlib during the simulation. This yields a slight performance advantage. Choosing a value forsion_chunksize
which is too large does not hurt that much because SIONlib container files are sparse files (if supported by the underlying file system) which only use up the disk space which is actually required by the stored data.- buffer_size
The size of task-specific buffers (default: 1024) within the sionlib recording backend in bytes. These buffers are used to temporarily store data generated by the recording devices on each task. As soon as a buffer is full, its contents are written to the respective container file. To achieve optimum performance, the size of these buffers should at least amount to the size of the file system blocks.
- sion_collective
Flag (default: false) to enable the collective mode of SIONlib. In collective mode, recorded data is buffered completely during
Run
and only written at the very end ofRun
to the container files, all tasks acting synchronously. Furthermore, within SIONlib so-called collectors aggregate data from a specific number of tasks, and actually only these collectors directly access the container files, in this way minimizing load on the file system. The number of tasks per collector is determined automatically by SIONlib. However, collector size can also be set explicitly by the user via the environment variable SION_COLLSIZE before the start of NEST. On large simulations which also generate a large amount of data, collective mode can offer a performance advantage.
Recording backend mpi - Send data with MPI¶
Description¶
Availability
This stimulation backend is only available if NEST was compiled with support for MPI.
The mpi recording backend sends collected data to a remote process using MPI.
There are two ways to set the MPI port. If both are set, option A has precedence
The address is supplied via the recording backends “mpi_address” status property.
The name of the MPI port to send data to is read from a file for each device configured to use this backend. The file needs to be named according to the following pattern:
{data_path}/{data_prefix}{label}/{node_id}.txt
The data_path
and data_prefix
are global kernel properties,
while label is a property of the device in question and node_id
its node ID. This path can only be set outside of a Run context
(i.e. after Prepare()
has been called, but Cleanup()
has not).
Communication Protocol¶
The following protocol is used to exchange information between both MPI processes. The protocol is described using the following format for the MPI messages: (value, number, type, source/destination, tag)
Prepare
: Connection of MPI port included in the port_file (see below)Run
begin: Send at each beginning of the run (true, 1, CXX_BOOL, 0, 0)Run
end : Receive at each ending of the run (true, 1, CXX_BOOL, 0, 0)Run
end : Send shape of the data of the run (shape, 1,INT, 0, 0)Run
end : Send data of the data of the run (data, shape, DOUBLE, 0, 0)Run
end : Send at each ending of the run (true, 1, CXX_BOOL, 0, 1)Cleanup
: Send at this en of the simulation (true, 1, CXX_BOOL, 0, 2)
Data format¶
The format of the data sent is an array consisting of (id device, id node, time is ms).