Skip to content

Commit

Permalink
Move HDF5RecordingData to its own hpp/cpp files
Browse files Browse the repository at this point in the history
  • Loading branch information
oruebel committed Sep 5, 2024
1 parent 04117e9 commit 82a4c08
Show file tree
Hide file tree
Showing 8 changed files with 200 additions and 164 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ add_library(
src/io/BaseIO.cpp
src/Channel.cpp
src/io/hdf5/HDF5IO.cpp
src/io/hdf5/HDF5RecordingData.cpp
src/nwb/NWBFile.cpp
src/nwb/RecordingContainers.cpp
src/nwb/base/TimeSeries.cpp
Expand Down
103 changes: 1 addition & 102 deletions src/io/hdf5/HDF5IO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <vector>

#include "io/hdf5/HDF5IO.hpp"
#include "io/hdf5/HDF5RecordingData.hpp"

#include <H5Cpp.h>
#include <H5Fpublic.h>
Expand Down Expand Up @@ -920,106 +921,4 @@ H5::DataType HDF5IO::getH5Type(IO::BaseDataType type)
return baseType;
}

// HDF5RecordingData
HDF5RecordingData::HDF5RecordingData(std::unique_ptr<H5::DataSet> data)
{
DataSpace dSpace = data->getSpace();
DSetCreatPropList prop = data->getCreatePlist();

int nDimensions = dSpace.getSimpleExtentNdims();
std::vector<hsize_t> dims(nDimensions), chunk(nDimensions);

nDimensions = dSpace.getSimpleExtentDims(
dims.data()); // TODO -redefine here or use original?
prop.getChunk(static_cast<int>(nDimensions), chunk.data());

this->size = std::vector<SizeType>(nDimensions);
for (int i = 0; i < nDimensions; ++i) {
this->size[i] = dims[i];
}
this->nDimensions = nDimensions;
this->position = std::vector<SizeType>(
nDimensions, 0); // Initialize position with 0 for each dimension
this->dSet = std::make_unique<H5::DataSet>(*data);
}

// HDF5RecordingData

HDF5RecordingData::~HDF5RecordingData()
{
// Safety
dSet->flush(H5F_SCOPE_GLOBAL);
}

Status HDF5RecordingData::writeDataBlock(
const std::vector<SizeType>& dataShape,
const std::vector<SizeType>& positionOffset,
const BaseDataType& type,
const void* data)
{
try {
// check dataShape and positionOffset inputs match the dimensions of the
// dataset
if (dataShape.size() != nDimensions || positionOffset.size() != nDimensions)
{
return Status::Failure;
}

// Ensure that we have enough space to accommodate new data
std::vector<hsize_t> dSetDims(nDimensions), offset(nDimensions);
for (int i = 0; i < nDimensions; ++i) {
offset[i] = static_cast<hsize_t>(positionOffset[i]);

if (dataShape[i] + offset[i] > size[i]) // TODO - do I need offset here
dSetDims[i] = dataShape[i] + offset[i];
else
dSetDims[i] = size[i];
}

// Adjust dataset dimensions if necessary
dSet->extend(dSetDims.data());

// Set size to new size based on updated dimensionality
DataSpace fSpace = dSet->getSpace();
fSpace.getSimpleExtentDims(dSetDims.data());
for (int i = 0; i < nDimensions; ++i) {
size[i] = dSetDims[i];
}

// Create memory space with the shape of the data
// DataSpace mSpace(dimension, dSetDim.data());
std::vector<hsize_t> dataDims(nDimensions);
for (int i = 0; i < nDimensions; ++i) {
if (dataShape[i] == 0) {
dataDims[i] = 1;
} else {
dataDims[i] = static_cast<hsize_t>(dataShape[i]);
}
}
DataSpace mSpace(static_cast<int>(nDimensions), dataDims.data());

// Select hyperslab in the file space
fSpace.selectHyperslab(H5S_SELECT_SET, dataDims.data(), offset.data());

// Write the data
DataType nativeType = HDF5IO::getNativeType(type);
dSet->write(data, nativeType, mSpace, fSpace);

// Update position for simple extension
for (int i = 0; i < dataShape.size(); ++i) {
position[i] += dataShape[i];
}
} catch (DataSetIException error) {
error.printErrorStack();
} catch (DataSpaceIException error) {
error.printErrorStack();
} catch (FileIException error) {
error.printErrorStack();
}
return Status::Success;
}

const H5::DataSet* HDF5RecordingData::getDataSet()
{
return dSet.get();
};
64 changes: 2 additions & 62 deletions src/io/hdf5/HDF5IO.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ class DataSpace;
*/
namespace AQNWB::IO::HDF5
{
class HDF5RecordingData; // declare here because gets used in HDF5IO class

class HDF5RecordingData; // forward declaration

/**
* @brief The HDF5IO class provides an interface for reading and writing data to
Expand Down Expand Up @@ -409,65 +410,4 @@ class HDF5IO : public BaseIO
bool disableSWMRMode;
};

/**
* @brief Represents an HDF5 Dataset that can be extended indefinitely
in blocks.
*
* This class provides functionality for reading and writing blocks of data
* to an HDF5 dataset.
*/
class HDF5RecordingData : public IO::BaseRecordingData
{
public:
/**
* @brief Constructs an HDF5RecordingData object.
* @param data A pointer to the HDF5 dataset.
*/
HDF5RecordingData(std::unique_ptr<H5::DataSet> data);

/**
* @brief Deleted copy constructor to prevent construction-copying.
*/
HDF5RecordingData(const HDF5RecordingData&) = delete;

/**
* @brief Deleted copy assignment operator to prevent copying.
*/
HDF5RecordingData& operator=(const HDF5RecordingData&) = delete;

/**
* @brief Destroys the HDF5RecordingData object.
*/
~HDF5RecordingData();

/**
* @brief Writes a block of data to the HDF5 dataset.
* @param dataShape The size of the data block.
* @param positionOffset The position of the data block to write to.
* @param type The data type of the elements in the data block.
* @param data A pointer to the data block.
* @return The status of the write operation.
*/
Status writeDataBlock(const std::vector<SizeType>& dataShape,
const std::vector<SizeType>& positionOffset,
const IO::BaseDataType& type,
const void* data);

/**
* @brief Gets a const pointer to the HDF5 dataset.
* @return A const pointer to the HDF5 dataset.
*/
const H5::DataSet* getDataSet();

private:
/**
* @brief Pointer to an extendable HDF5 dataset
*/
std::unique_ptr<H5::DataSet> dSet;

/**
* @brief Return status of HDF5 operations.
*/
Status checkStatus(int status);
};
} // namespace AQNWB::IO::HDF5
119 changes: 119 additions & 0 deletions src/io/hdf5/HDF5RecordingData.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#include <codecvt>
#include <filesystem>
#include <iostream>
#include <memory>
#include <vector>

#include "io/hdf5/HDF5RecordingData.hpp"

#include <H5Cpp.h>
#include <H5Fpublic.h>

#include "Utils.hpp"

using namespace H5;
using namespace AQNWB::IO::HDF5;

// HDF5RecordingData
HDF5RecordingData::HDF5RecordingData(std::unique_ptr<H5::DataSet> data)
{
DataSpace dSpace = data->getSpace();
DSetCreatPropList prop = data->getCreatePlist();

int nDimensions = dSpace.getSimpleExtentNdims();
std::vector<hsize_t> dims(nDimensions), chunk(nDimensions);

nDimensions = dSpace.getSimpleExtentDims(
dims.data()); // TODO -redefine here or use original?
prop.getChunk(static_cast<int>(nDimensions), chunk.data());

this->size = std::vector<SizeType>(nDimensions);
for (int i = 0; i < nDimensions; ++i) {
this->size[i] = dims[i];
}
this->nDimensions = nDimensions;
this->position = std::vector<SizeType>(
nDimensions, 0); // Initialize position with 0 for each dimension
this->dSet = std::make_unique<H5::DataSet>(*data);
}

// HDF5RecordingData

HDF5RecordingData::~HDF5RecordingData()
{
// Safety
dSet->flush(H5F_SCOPE_GLOBAL);
}

Status HDF5RecordingData::writeDataBlock(
const std::vector<SizeType>& dataShape,
const std::vector<SizeType>& positionOffset,
const BaseDataType& type,
const void* data)
{
try {
// check dataShape and positionOffset inputs match the dimensions of the
// dataset
if (dataShape.size() != nDimensions || positionOffset.size() != nDimensions)
{
return Status::Failure;
}

// Ensure that we have enough space to accommodate new data
std::vector<hsize_t> dSetDims(nDimensions), offset(nDimensions);
for (int i = 0; i < nDimensions; ++i) {
offset[i] = static_cast<hsize_t>(positionOffset[i]);

if (dataShape[i] + offset[i] > size[i]) // TODO - do I need offset here
dSetDims[i] = dataShape[i] + offset[i];
else
dSetDims[i] = size[i];
}

// Adjust dataset dimensions if necessary
dSet->extend(dSetDims.data());

// Set size to new size based on updated dimensionality
DataSpace fSpace = dSet->getSpace();
fSpace.getSimpleExtentDims(dSetDims.data());
for (int i = 0; i < nDimensions; ++i) {
size[i] = dSetDims[i];
}

// Create memory space with the shape of the data
// DataSpace mSpace(dimension, dSetDim.data());
std::vector<hsize_t> dataDims(nDimensions);
for (int i = 0; i < nDimensions; ++i) {
if (dataShape[i] == 0) {
dataDims[i] = 1;
} else {
dataDims[i] = static_cast<hsize_t>(dataShape[i]);
}
}
DataSpace mSpace(static_cast<int>(nDimensions), dataDims.data());

// Select hyperslab in the file space
fSpace.selectHyperslab(H5S_SELECT_SET, dataDims.data(), offset.data());

// Write the data
DataType nativeType = HDF5IO::getNativeType(type);
dSet->write(data, nativeType, mSpace, fSpace);

// Update position for simple extension
for (int i = 0; i < dataShape.size(); ++i) {
position[i] += dataShape[i];
}
} catch (DataSetIException error) {
error.printErrorStack();
} catch (DataSpaceIException error) {
error.printErrorStack();
} catch (FileIException error) {
error.printErrorStack();
}
return Status::Success;
}

const H5::DataSet* HDF5RecordingData::getDataSet()
{
return dSet.get();
};
74 changes: 74 additions & 0 deletions src/io/hdf5/HDF5RecordingData.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#pragma once

#include "io/BaseIO.hpp"


namespace H5
{
class DataSet;
} // namespace H5

namespace AQNWB::IO::HDF5
{
/**
* @brief Represents an HDF5 Dataset that can be extended indefinitely
* in blocks.
*
* This class provides functionality for reading and writing blocks of data
* to an HDF5 dataset.
*/
class HDF5RecordingData : public AQNWB::IO::BaseRecordingData
{
public:
/**
* @brief Constructs an HDF5RecordingData object.
* @param data A pointer to the HDF5 dataset.
*/
HDF5RecordingData(std::unique_ptr<H5::DataSet> data);

/**
* @brief Deleted copy constructor to prevent construction-copying.
*/
HDF5RecordingData(const HDF5RecordingData&) = delete;

/**
* @brief Deleted copy assignment operator to prevent copying.
*/
HDF5RecordingData& operator=(const HDF5RecordingData&) = delete;

/**
* @brief Destroys the HDF5RecordingData object.
*/
~HDF5RecordingData();

/**
* @brief Writes a block of data to the HDF5 dataset.
* @param dataShape The size of the data block.
* @param positionOffset The position of the data block to write to.
* @param type The data type of the elements in the data block.
* @param data A pointer to the data block.
* @return The status of the write operation.
*/
Status writeDataBlock(const std::vector<SizeType>& dataShape,
const std::vector<SizeType>& positionOffset,
const AQNWB::IO::BaseDataType& type,
const void* data);

/**
* @brief Gets a const pointer to the HDF5 dataset.
* @return A const pointer to the HDF5 dataset.
*/
const H5::DataSet* getDataSet();

private:
/**
* @brief Pointer to an extendable HDF5 dataset
*/
std::unique_ptr<H5::DataSet> dSet;

/**
* @brief Return status of HDF5 operations.
*/
Status checkStatus(int status);
};
} // namespace AQNWB::IO::HDF5
Loading

0 comments on commit 82a4c08

Please sign in to comment.