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 field times, interpreted as the simulation time in ms

  • If 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 in times and the negative offset from the next such grid point as a floating point number in ms in offset.

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 of time_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 the events dictionary) plus a floating point number for the negative offset from the next grid point in ms (under key offset), or just the simulation time in ms under key times. 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 backend

  • The 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.

NEST SIONlib binary file format

Figure 18 NEST SIONlib binary file format.

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 single Prepare-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 for sion_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 of Run 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

  1. The address is supplied via the recording backends “mpi_address” status property.

  2. 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)

  1. Prepare : Connection of MPI port included in the port_file (see below)

  2. Run begin: Send at each beginning of the run (true, 1, CXX_BOOL, 0, 0)

  3. Run end : Receive at each ending of the run (true, 1, CXX_BOOL, 0, 0)

  4. Run end : Send shape of the data of the run (shape, 1,INT, 0, 0)

  5. Run end : Send data of the data of the run (data, shape, DOUBLE, 0, 0)

  6. Run end : Send at each ending of the run (true, 1, CXX_BOOL, 0, 1)

  7. 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).