-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add AnnotationSeries data type (#141)
* add initial AnnotationSeries implementation * add convenience functions, remove dtype option * add draft of tests * update writeDataBlock error message * update AnnotationSeries methods for vlen strings * add tests * fix formatting * Update src/nwb/misc/AnnotationSeries.hpp Co-authored-by: Oliver Ruebel <[email protected]> * update read example in tests --------- Co-authored-by: Oliver Ruebel <[email protected]>
- Loading branch information
1 parent
6b1dbc6
commit d76f8b7
Showing
11 changed files
with
351 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
|
||
#include "nwb/misc/AnnotationSeries.hpp" | ||
|
||
#include "Utils.hpp" | ||
|
||
using namespace AQNWB::NWB; | ||
|
||
// AnnotationSeries | ||
// Initialize the static registered_ member to trigger registration | ||
REGISTER_SUBCLASS_IMPL(AnnotationSeries) | ||
|
||
/** Constructor */ | ||
AnnotationSeries::AnnotationSeries(const std::string& path, | ||
std::shared_ptr<IO::BaseIO> io) | ||
: TimeSeries(path, io) | ||
{ | ||
} | ||
|
||
/** Destructor */ | ||
AnnotationSeries::~AnnotationSeries() {} | ||
|
||
/** Initialization function*/ | ||
void AnnotationSeries::initialize(const std::string& description, | ||
const std::string& comments, | ||
const SizeArray& dsetSize, | ||
const SizeArray& chunkSize) | ||
{ | ||
TimeSeries::initialize( | ||
IO::BaseDataType::V_STR, // fixed to string according to schema | ||
"n/a", // unit fixed to "n/a" | ||
description, | ||
comments, | ||
dsetSize, | ||
chunkSize, | ||
1.0f, // conversion fixed to 1.0, since unit is n/a | ||
-1.0f, // resolution fixed to -1.0 | ||
0.0f); // offset fixed to 0.0, since unit is n/a | ||
} | ||
|
||
Status AnnotationSeries::writeAnnotation(const SizeType& numSamples, | ||
std::vector<std::string> dataInput, | ||
const void* timestampsInput, | ||
const void* controlInput) | ||
{ | ||
std::vector<SizeType> dataShape = {numSamples}; | ||
std::vector<SizeType> positionOffset = {this->m_samplesRecorded}; | ||
|
||
// Write timestamps | ||
Status tsStatus = Status::Success; | ||
tsStatus = this->timestamps->writeDataBlock( | ||
dataShape, positionOffset, this->timestampsType, timestampsInput); | ||
|
||
// Write the data | ||
Status dataStatus = this->data->writeDataBlock( | ||
dataShape, positionOffset, this->m_dataType, dataInput); | ||
|
||
// Write the control data if it exists | ||
if (controlInput != nullptr) { | ||
tsStatus = this->control->writeDataBlock( | ||
dataShape, positionOffset, this->controlType, controlInput); | ||
} | ||
|
||
// track samples recorded | ||
m_samplesRecorded += numSamples; | ||
|
||
if ((dataStatus != Status::Success) || (tsStatus != Status::Success)) { | ||
return Status::Failure; | ||
} else { | ||
return Status::Success; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
|
||
#pragma once | ||
|
||
#include <string> | ||
|
||
#include "Utils.hpp" | ||
#include "io/BaseIO.hpp" | ||
#include "io/ReadIO.hpp" | ||
#include "nwb/base/TimeSeries.hpp" | ||
|
||
namespace AQNWB::NWB | ||
{ | ||
/** | ||
* @brief TimeSeries storing text-based records about the experiment. | ||
*/ | ||
class AnnotationSeries : public TimeSeries | ||
{ | ||
public: | ||
// Register the AnnotationSeries | ||
REGISTER_SUBCLASS(AnnotationSeries, "core") | ||
|
||
/** | ||
* @brief Constructor. | ||
* @param path The location of the AnnotationSeries in the file. | ||
* @param io A shared pointer to the IO object. | ||
*/ | ||
AnnotationSeries(const std::string& path, std::shared_ptr<IO::BaseIO> io); | ||
|
||
/** | ||
* @brief Destructor | ||
*/ | ||
~AnnotationSeries(); | ||
|
||
/** | ||
* @brief Initializes the AnnotationSeries | ||
* @param description The description of the AnnotationSeries. | ||
* @param dsetSize Initial size of the main dataset. This must be a vector | ||
* with one element specifying the length in time. | ||
* @param chunkSize Chunk size to use. | ||
*/ | ||
void initialize(const std::string& description, | ||
const std::string& comments, | ||
const SizeArray& dsetSize, | ||
const SizeArray& chunkSize); | ||
|
||
/** | ||
* @brief Writes a channel to an AnnotationSeries dataset. | ||
* @param numSamples The number of samples to write (length in time). | ||
* @param dataInput A vector of strings. | ||
* @param timestampsInput A pointer to the timestamps block. | ||
* @param controlInput A pointer to the control block data (optional) | ||
* @return The status of the write operation. | ||
*/ | ||
Status writeAnnotation(const SizeType& numSamples, | ||
const std::vector<std::string> dataInput, | ||
const void* timestampsInput, | ||
const void* controlInput = nullptr); | ||
|
||
DEFINE_FIELD(readData, | ||
DatasetField, | ||
std::string, | ||
"data", | ||
Annotations made during an experiment.) | ||
|
||
private: | ||
/** | ||
* @brief The number of samples already written per channel. | ||
*/ | ||
SizeType m_samplesRecorded = 0; | ||
}; | ||
} // namespace AQNWB::NWB |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
#include <H5Cpp.h> | ||
#include <catch2/catch_test_macros.hpp> | ||
#include <catch2/matchers/catch_matchers_all.hpp> | ||
|
||
#include "Types.hpp" | ||
#include "Utils.hpp" | ||
#include "io/BaseIO.hpp" | ||
#include "nwb/misc/AnnotationSeries.hpp" | ||
#include "testUtils.hpp" | ||
|
||
using namespace AQNWB; | ||
|
||
TEST_CASE("AnnotationSeries", "[misc]") | ||
{ | ||
// setup recording info | ||
SizeType numSamples = 3; | ||
std::string dataPath = "/annotations"; | ||
std::vector<std::string> mockAnnotations = { | ||
"Subject moved", | ||
"Break started", | ||
"Break ended", | ||
}; | ||
std::vector<double> mockTimestamps = getMockTimestamps(numSamples, 1); | ||
std::vector<double> mockTimestamps2 = mockTimestamps; | ||
for (double& value : mockTimestamps2) { | ||
value += 5; | ||
} | ||
|
||
SECTION("test writing annotations") | ||
{ | ||
// setup io object | ||
std::string path = getTestFilePath("AnnotationSeries.h5"); | ||
std::shared_ptr<BaseIO> io = createIO("HDF5", path); | ||
io->open(); | ||
|
||
// setup annotation series | ||
NWB::AnnotationSeries as = NWB::AnnotationSeries(dataPath, io); | ||
as.initialize( | ||
"Test annotations", "Test comments", SizeArray {0}, SizeArray {1}); | ||
|
||
// write annotations multiple times to test adding to same dataset | ||
Status writeStatus = | ||
as.writeAnnotation(numSamples, mockAnnotations, mockTimestamps.data()); | ||
REQUIRE(writeStatus == Status::Success); | ||
Status writeStatus2 = | ||
as.writeAnnotation(numSamples, mockAnnotations, mockTimestamps2.data()); | ||
REQUIRE(writeStatus2 == Status::Success); | ||
io->flush(); | ||
|
||
// Read annotations back from file | ||
std::vector<std::string> expectedAnnotations = mockAnnotations; | ||
expectedAnnotations.insert(expectedAnnotations.end(), | ||
mockAnnotations.begin(), | ||
mockAnnotations.end()); | ||
std::vector<std::string> dataOut(expectedAnnotations.size()); | ||
|
||
auto readDataWrapper = as.readData(); | ||
auto readAnnotationsDataTyped = readDataWrapper->values(); | ||
REQUIRE(readAnnotationsDataTyped.data == expectedAnnotations); | ||
|
||
// Read timestamps | ||
std::vector<double> expectedTimestamps = mockTimestamps; | ||
expectedTimestamps.insert(expectedTimestamps.end(), | ||
mockTimestamps2.begin(), | ||
mockTimestamps2.end()); | ||
std::vector<double> timestampsOut(expectedTimestamps.size()); | ||
|
||
auto readTimestampsWrapper = as.readTimestamps(); | ||
auto readTimestampsDataTyped = readTimestampsWrapper->values(); | ||
REQUIRE_THAT(readTimestampsDataTyped.data, | ||
Catch::Matchers::Approx(expectedTimestamps)); | ||
} | ||
} |
Oops, something went wrong.