aqnwb 0.1.0
Loading...
Searching...
No Matches
AqNWB Workflow

Overview of a recording workflow

For users wanting to integrate NWB with a particular data acquisition software, here we outline the steps for a single recording from file creation to saving.

  1. Create the I/O object (e.g,. HDF5IO) used for writing data to the file on disk.
  2. Create the RecordingContainers object used for managing Container objects for storing recordings.
  3. Create the NWBFile object used for managing and creating NWB file contents.
  4. Create the Container objects (e.g., ElectricalSeries) used for recording and add them to the RecordingContainers.
  5. Start the recording.
  6. Write data.
  7. Stop the recording and close the NWBFile.

Below, we walk through these steps in more detail.

1. Create the I/O object.

First, create an I/O object (e.g., HDF5IO) used for writing data to the file. AqNWB provides the convenience method, createIO to create this object using one of the supported backends. For more fine-grained control of different backend parameters, you can create your own std::shared_ptr using any of the derived BaseIO classes.

std::shared_ptr<BaseIO> io = createIO("HDF5", path);

2. Create the RecordingContainer object.

Next, create a RecordingContainers object to manage the different Container objects with the datasets that you would like to write data to.

std::unique_ptr<NWB::RecordingContainers> recordingContainers =
std::make_unique<NWB::RecordingContainers>();

3. Create the NWBFile

Next, constructs the NWBFile object, using the I/O object as an input. Then, initialize the object to create the basic file structure of the NWBFile.

std::unique_ptr<NWB::NWBFile> nwbfile =
std::make_unique<NWB::NWBFile>(generateUuid(), io);
nwbfile->initialize();

4. Create datasets and add to RecordingContainers.

Next, create the different data types (e.g. ElectricalSeries or other AQNWB::NWB::TimeSeries "TimeSeries") that you would like to write data into. After creation, these objects are added to the RecordingContainers object so that it can mana ge access and data writing during the recording process. When adding containers, ownership of the Container is transferred to the RecordingContainers object, so that we can access it again via its index. New containers will always be appended to the end of the private member `RecordingContainers.m_containers object and their index can be tracked using the RecordingContainers.size of the input recordingArrays.

std::vector<SizeType> containerIndexes;
nwbfile->createElectricalSeries(mockRecordingArrays,
mockChannelNames,
BaseDataType::I16,
recordingContainers.get(),
containerIndexes);

5. Start the recording.

Then, start the recording process with a call to the startRecording function of the I/O object.

Note
When using HDF5IO for writing to HDF5, calling startRecording will by default enable SWMR mode to ensure file integrity and support concurrent read. As a result, no additional datasets or groups can be added to the file once a recording has been started unless the file is is closed and reopened.
io->startRecording();

6. Write data.

During the recording process, use the RecordingContainers as an interface to access the various Container object and corresponding datasets and write blocks of data to the file. Calling flush() on the I/O object at any time will ensure the data is moved to disk.

recordingContainers->writeTimeseriesData(containerIndexes[i],
channel,
dataShape,
positionOffset,
intBuffer.get(),
timestampsBuffer.data());
io->flush();

7. Stop the recording and finalize the file.

When the recording process is finished, call stopRecording from the I/O object to flush any data and close the file.

io->stopRecording();
nwbfile->finalize();