mirror of
https://github.com/slsdetectorgroup/aare.git
synced 2025-06-22 11:37:59 +02:00
WIP
This commit is contained in:
33
src/CMakeLists.txt
Normal file
33
src/CMakeLists.txt
Normal file
@ -0,0 +1,33 @@
|
||||
|
||||
|
||||
set(SourceFiles
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/defs.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Dtype.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Frame.cpp
|
||||
)
|
||||
|
||||
|
||||
add_library(aare_core STATIC ${SourceFiles})
|
||||
target_include_directories(aare_core PUBLIC ${CMAKE_SOURCE_DIR}/include)
|
||||
target_link_libraries(aare_core PUBLIC fmt::fmt PRIVATE aare_compiler_flags )
|
||||
|
||||
if (AARE_PYTHON_BINDINGS)
|
||||
set_property(TARGET aare_core PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
endif()
|
||||
|
||||
if(AARE_TESTS)
|
||||
set(TestSources
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/defs.test.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Dtype.test.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Frame.test.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/test/ProducerConsumerQueue.test.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/NDArray.test.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/NDView.test.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/test/CircularFifo.test.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/test/wrappers.test.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/test/Transforms.test.cpp
|
||||
|
||||
)
|
||||
target_sources(tests PRIVATE ${TestSources} )
|
||||
target_link_libraries(tests PRIVATE aare_core)
|
||||
endif()
|
191
src/Dtype.cpp
Normal file
191
src/Dtype.cpp
Normal file
@ -0,0 +1,191 @@
|
||||
|
||||
#include "aare/Dtype.hpp"
|
||||
#include "aare/defs.hpp"
|
||||
|
||||
#include <fmt/core.h>
|
||||
|
||||
namespace aare {
|
||||
|
||||
/**
|
||||
* @brief Construct a DType object from a type_info object
|
||||
* @param t type_info object
|
||||
* @throw runtime_error if the type is not supported
|
||||
* @note supported types are: int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t, float, double
|
||||
* @note the type_info object is obtained using typeid (e.g. typeid(int))
|
||||
*/
|
||||
Dtype::Dtype(const std::type_info &t) {
|
||||
if (t == typeid(int8_t))
|
||||
m_type = TypeIndex::INT8;
|
||||
else if (t == typeid(uint8_t))
|
||||
m_type = TypeIndex::UINT8;
|
||||
else if (t == typeid(int16_t))
|
||||
m_type = TypeIndex::INT16;
|
||||
else if (t == typeid(uint16_t))
|
||||
m_type = TypeIndex::UINT16;
|
||||
else if (t == typeid(int32_t))
|
||||
m_type = TypeIndex::INT32;
|
||||
else if (t == typeid(uint32_t))
|
||||
m_type = TypeIndex::UINT32;
|
||||
else if (t == typeid(int64_t)) // NOLINT
|
||||
m_type = TypeIndex::INT64;
|
||||
else if (t == typeid(uint64_t))
|
||||
m_type = TypeIndex::UINT64;
|
||||
else if (t == typeid(float))
|
||||
m_type = TypeIndex::FLOAT;
|
||||
else if (t == typeid(double))
|
||||
m_type = TypeIndex::DOUBLE;
|
||||
else
|
||||
throw std::runtime_error("Could not construct data type. Type not supported.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the bitdepth of the data type
|
||||
* @return bitdepth
|
||||
*/
|
||||
uint8_t Dtype::bitdepth() const {
|
||||
switch (m_type) {
|
||||
case TypeIndex::INT8:
|
||||
case TypeIndex::UINT8:
|
||||
return 8;
|
||||
case TypeIndex::INT16:
|
||||
case TypeIndex::UINT16:
|
||||
return 16;
|
||||
case TypeIndex::INT32:
|
||||
case TypeIndex::UINT32:
|
||||
return 32;
|
||||
case TypeIndex::INT64:
|
||||
case TypeIndex::UINT64:
|
||||
return 64;
|
||||
case TypeIndex::FLOAT:
|
||||
return 32;
|
||||
case TypeIndex::DOUBLE:
|
||||
return 64;
|
||||
case TypeIndex::NONE:
|
||||
return 0;
|
||||
default:
|
||||
throw std::runtime_error(LOCATION + "Could not get bitdepth. Type not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the number of bytes of the data type
|
||||
*/
|
||||
size_t Dtype::bytes() const { return bitdepth() / 8; }
|
||||
|
||||
/**
|
||||
* @brief Construct a DType object from a TypeIndex
|
||||
* @param ti TypeIndex
|
||||
*
|
||||
*/
|
||||
Dtype::Dtype(Dtype::TypeIndex ti) : m_type(ti) {}
|
||||
|
||||
/**
|
||||
* @brief Construct a DType object from a string
|
||||
* @param sv string_view
|
||||
* @throw runtime_error if the type is not supported
|
||||
* @note example strings: "<i4", "u8", "f4"
|
||||
* @note the endianess is checked and only native endianess is supported
|
||||
*/
|
||||
Dtype::Dtype(std::string_view sv) {
|
||||
|
||||
// Check if the file is using our native endianess
|
||||
if (auto pos = sv.find_first_of("<>"); pos != std::string_view::npos) {
|
||||
const auto endianess = [](const char c) {
|
||||
if (c == '<')
|
||||
return endian::little;
|
||||
return endian::big;
|
||||
}(sv[pos]);
|
||||
if (endianess != endian::native) {
|
||||
throw std::runtime_error("Non native endianess not supported");
|
||||
}
|
||||
}
|
||||
|
||||
// we are done with the endianess so we can remove the prefix
|
||||
sv.remove_prefix(std::min(sv.find_first_not_of("<>"), sv.size()));
|
||||
|
||||
if (sv == "i1")
|
||||
m_type = TypeIndex::INT8;
|
||||
else if (sv == "u1")
|
||||
m_type = TypeIndex::UINT8;
|
||||
else if (sv == "i2")
|
||||
m_type = TypeIndex::INT16;
|
||||
else if (sv == "u2")
|
||||
m_type = TypeIndex::UINT16;
|
||||
else if (sv == "i4")
|
||||
m_type = TypeIndex::INT32;
|
||||
else if (sv == "u4")
|
||||
m_type = TypeIndex::UINT32;
|
||||
else if (sv == "i8")
|
||||
m_type = TypeIndex::INT64;
|
||||
else if (sv == "u8")
|
||||
m_type = TypeIndex::UINT64;
|
||||
else if (sv == "f4")
|
||||
m_type = TypeIndex::FLOAT;
|
||||
else if (sv == "f8")
|
||||
m_type = TypeIndex::DOUBLE;
|
||||
else
|
||||
throw std::runtime_error("Cannot construct data type from string.");
|
||||
}
|
||||
|
||||
Dtype Dtype::from_bitdepth(uint8_t bitdepth) {
|
||||
switch (bitdepth) {
|
||||
case 8:
|
||||
return Dtype(TypeIndex::UINT8);
|
||||
case 16:
|
||||
return Dtype(TypeIndex::UINT16);
|
||||
case 32:
|
||||
return Dtype(TypeIndex::UINT32);
|
||||
case 64:
|
||||
return Dtype(TypeIndex::UINT64);
|
||||
default:
|
||||
throw std::runtime_error("Could not construct data type from bitdepth.");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Get the string representation of the data type
|
||||
* @return string representation
|
||||
*/
|
||||
std::string Dtype::to_string() const {
|
||||
|
||||
char ec{};
|
||||
if (endian::native == endian::little)
|
||||
ec = '<';
|
||||
else
|
||||
ec = '>';
|
||||
|
||||
switch (m_type) {
|
||||
case TypeIndex::INT8:
|
||||
return fmt::format("{}i1", ec);
|
||||
case TypeIndex::UINT8:
|
||||
return fmt::format("{}u1", ec);
|
||||
case TypeIndex::INT16:
|
||||
return fmt::format("{}i2", ec);
|
||||
case TypeIndex::UINT16:
|
||||
return fmt::format("{}u2", ec);
|
||||
case TypeIndex::INT32:
|
||||
return fmt::format("{}i4", ec);
|
||||
case TypeIndex::UINT32:
|
||||
return fmt::format("{}u4", ec);
|
||||
case TypeIndex::INT64:
|
||||
return fmt::format("{}i8", ec);
|
||||
case TypeIndex::UINT64:
|
||||
return fmt::format("{}u8", ec);
|
||||
case TypeIndex::FLOAT:
|
||||
return "f4";
|
||||
case TypeIndex::DOUBLE:
|
||||
return "f8";
|
||||
case TypeIndex::ERROR:
|
||||
throw std::runtime_error("Could not get string representation. Type not supported.");
|
||||
case TypeIndex::NONE:
|
||||
throw std::runtime_error("Could not get string representation. Type not supported.");
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool Dtype::operator==(const Dtype &other) const noexcept { return m_type == other.m_type; }
|
||||
bool Dtype::operator!=(const Dtype &other) const noexcept { return !(*this == other); }
|
||||
|
||||
bool Dtype::operator==(const std::type_info &t) const { return Dtype(t) == *this; }
|
||||
bool Dtype::operator!=(const std::type_info &t) const { return Dtype(t) != *this; }
|
||||
|
||||
} // namespace aare
|
54
src/Dtype.test.cpp
Normal file
54
src/Dtype.test.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
|
||||
|
||||
#include "aare/Dtype.hpp"
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
using aare::Dtype;
|
||||
using aare::endian;
|
||||
|
||||
TEST_CASE("Construct from typeid") {
|
||||
REQUIRE(Dtype(typeid(int)) == typeid(int));
|
||||
REQUIRE(Dtype(typeid(int)) != typeid(double));
|
||||
}
|
||||
|
||||
TEST_CASE("Construct from string") {
|
||||
if (endian::native == endian::little) {
|
||||
REQUIRE(Dtype("<i1") == typeid(int8_t));
|
||||
REQUIRE(Dtype("<u1") == typeid(uint8_t));
|
||||
REQUIRE(Dtype("<i2") == typeid(int16_t));
|
||||
REQUIRE(Dtype("<u2") == typeid(uint16_t));
|
||||
REQUIRE(Dtype("<i4") == typeid(int));
|
||||
REQUIRE(Dtype("<u4") == typeid(unsigned));
|
||||
REQUIRE(Dtype("<i4") == typeid(int32_t));
|
||||
// REQUIRE(Dtype("<i8") == typeid(long));
|
||||
REQUIRE(Dtype("<i8") == typeid(int64_t));
|
||||
REQUIRE(Dtype("<u4") == typeid(uint32_t));
|
||||
REQUIRE(Dtype("<u8") == typeid(uint64_t));
|
||||
REQUIRE(Dtype("f4") == typeid(float));
|
||||
REQUIRE(Dtype("f8") == typeid(double));
|
||||
}
|
||||
|
||||
if (endian::native == endian::big) {
|
||||
REQUIRE(Dtype(">i1") == typeid(int8_t));
|
||||
REQUIRE(Dtype(">u1") == typeid(uint8_t));
|
||||
REQUIRE(Dtype(">i2") == typeid(int16_t));
|
||||
REQUIRE(Dtype(">u2") == typeid(uint16_t));
|
||||
REQUIRE(Dtype(">i4") == typeid(int));
|
||||
REQUIRE(Dtype(">u4") == typeid(unsigned));
|
||||
REQUIRE(Dtype(">i4") == typeid(int32_t));
|
||||
// REQUIRE(Dtype(">i8") == typeid(long));
|
||||
REQUIRE(Dtype(">i8") == typeid(int64_t));
|
||||
REQUIRE(Dtype(">u4") == typeid(uint32_t));
|
||||
REQUIRE(Dtype(">u8") == typeid(uint64_t));
|
||||
REQUIRE(Dtype("f4") == typeid(float));
|
||||
REQUIRE(Dtype("f8") == typeid(double));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Construct from string with endianess") {
|
||||
// TODO! handle big endian system in test!
|
||||
REQUIRE(Dtype("<i4") == typeid(int32_t));
|
||||
REQUIRE_THROWS(Dtype(">i4") == typeid(int32_t));
|
||||
}
|
||||
|
||||
TEST_CASE("Convert to string") { REQUIRE(Dtype(typeid(int)).to_string() == "<i4"); }
|
110
src/Frame.cpp
Normal file
110
src/Frame.cpp
Normal file
@ -0,0 +1,110 @@
|
||||
#include "aare/Frame.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace aare {
|
||||
|
||||
/**
|
||||
* @brief Construct a new Frame
|
||||
* @param bytes pointer to the data to be copied into the frame
|
||||
* @param rows number of rows
|
||||
* @param cols number of columns
|
||||
* @param bitdepth bitdepth of the pixels
|
||||
*/
|
||||
Frame::Frame(const std::byte *bytes, uint32_t rows, uint32_t cols, Dtype dtype)
|
||||
: m_rows(rows), m_cols(cols), m_dtype(dtype), m_data(new std::byte[rows * cols * m_dtype.bytes()]) {
|
||||
|
||||
std::memcpy(m_data, bytes, rows * cols * m_dtype.bytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a new Frame
|
||||
* @param rows number of rows
|
||||
* @param cols number of columns
|
||||
* @param bitdepth bitdepth of the pixels
|
||||
* @note the data is initialized to zero
|
||||
*/
|
||||
Frame::Frame(uint32_t rows, uint32_t cols, Dtype dtype)
|
||||
: m_rows(rows), m_cols(cols), m_dtype(dtype), m_data(new std::byte[rows * cols * dtype.bytes()]) {
|
||||
|
||||
std::memset(m_data, 0, rows * cols * dtype.bytes());
|
||||
}
|
||||
|
||||
uint32_t Frame::rows() const { return m_rows; }
|
||||
uint32_t Frame::cols() const { return m_cols; }
|
||||
size_t Frame::bitdepth() const { return m_dtype.bitdepth(); }
|
||||
Dtype Frame::dtype() const { return m_dtype; }
|
||||
uint64_t Frame::size() const { return m_rows * m_cols; }
|
||||
size_t Frame::bytes() const { return m_rows * m_cols * m_dtype.bytes(); }
|
||||
std::byte *Frame::data() const { return m_data; }
|
||||
|
||||
/**
|
||||
* @brief Get the pointer to the pixel at the given row and column
|
||||
* @param row row index
|
||||
* @param col column index
|
||||
* @return pointer to the pixel
|
||||
* @note the user should cast the pointer to the appropriate type
|
||||
*/
|
||||
std::byte *Frame::get(uint32_t row, uint32_t col) {
|
||||
if ((row >= m_rows) || (col >= m_cols)) {
|
||||
std::cerr << "Invalid row or column index" << '\n';
|
||||
return nullptr;
|
||||
}
|
||||
return m_data + (row * m_cols + col) * (m_dtype.bytes());
|
||||
}
|
||||
|
||||
// Frame &Frame::operator=(const Frame &other) {
|
||||
// if (this == &other) {
|
||||
// return *this;
|
||||
// }
|
||||
// m_rows = other.rows();
|
||||
// m_cols = other.cols();
|
||||
// m_dtype = other.dtype();
|
||||
// m_data = new std::byte[m_rows * m_cols * m_dtype.bytes()];
|
||||
// if (m_data == nullptr) {
|
||||
// throw std::bad_alloc();
|
||||
// }
|
||||
// std::memcpy(m_data, other.m_data, m_rows * m_cols * m_dtype.bytes());
|
||||
// return *this;
|
||||
// }
|
||||
Frame &Frame::operator=(Frame &&other) noexcept {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
m_rows = other.rows();
|
||||
m_cols = other.cols();
|
||||
m_dtype = other.dtype();
|
||||
if (m_data != nullptr) {
|
||||
delete[] m_data;
|
||||
}
|
||||
m_data = other.m_data;
|
||||
other.m_data = nullptr;
|
||||
other.m_rows = other.m_cols = 0;
|
||||
other.m_dtype = Dtype(Dtype::TypeIndex::ERROR);
|
||||
return *this;
|
||||
}
|
||||
Frame::Frame(Frame &&other) noexcept
|
||||
: m_rows(other.rows()), m_cols(other.cols()), m_dtype(other.dtype()), m_data(other.m_data) {
|
||||
|
||||
other.m_data = nullptr;
|
||||
other.m_rows = other.m_cols = 0;
|
||||
other.m_dtype = Dtype(Dtype::TypeIndex::ERROR);
|
||||
}
|
||||
// Frame::Frame(const Frame &other)
|
||||
// : m_rows(other.rows()), m_cols(other.cols()), m_dtype(other.dtype()),
|
||||
// m_data(new std::byte[m_rows * m_cols * m_dtype.bytes()]) {
|
||||
|
||||
// std::memcpy(m_data, other.m_data, m_rows * m_cols * m_dtype.bytes());
|
||||
// }
|
||||
|
||||
Frame Frame::copy() const {
|
||||
Frame frame(m_rows, m_cols, m_dtype);
|
||||
std::memcpy(frame.m_data, m_data, m_rows * m_cols * m_dtype.bytes());
|
||||
return frame;
|
||||
}
|
||||
|
||||
Frame::~Frame() noexcept { delete[] m_data; }
|
||||
} // namespace aare
|
152
src/Frame.test.cpp
Normal file
152
src/Frame.test.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
#include "aare/Frame.hpp"
|
||||
#include "aare/Dtype.hpp"
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
using namespace aare;
|
||||
|
||||
TEST_CASE("Construct a frame") {
|
||||
size_t rows = 10;
|
||||
size_t cols = 10;
|
||||
size_t bitdepth = 8;
|
||||
|
||||
Frame frame(rows, cols, Dtype::from_bitdepth(bitdepth));
|
||||
|
||||
REQUIRE(frame.rows() == rows);
|
||||
REQUIRE(frame.cols() == cols);
|
||||
REQUIRE(frame.bitdepth() == bitdepth);
|
||||
REQUIRE(frame.bytes() == rows * cols * bitdepth / 8);
|
||||
|
||||
// data should be initialized to 0
|
||||
for (size_t i = 0; i < rows; i++) {
|
||||
for (size_t j = 0; j < cols; j++) {
|
||||
uint8_t *data = (uint8_t *)frame.get(i, j);
|
||||
REQUIRE(data != nullptr);
|
||||
REQUIRE(*data == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Set a value in a 8 bit frame") {
|
||||
size_t rows = 10;
|
||||
size_t cols = 10;
|
||||
size_t bitdepth = 8;
|
||||
|
||||
Frame frame(rows, cols, Dtype::from_bitdepth(bitdepth));
|
||||
|
||||
// set a value
|
||||
uint8_t value = 255;
|
||||
frame.set(5, 7, value);
|
||||
|
||||
// only the value we did set should be non-zero
|
||||
for (size_t i = 0; i < rows; i++) {
|
||||
for (size_t j = 0; j < cols; j++) {
|
||||
uint8_t *data = (uint8_t *)frame.get(i, j);
|
||||
REQUIRE(data != nullptr);
|
||||
if (i == 5 && j == 7) {
|
||||
REQUIRE(*data == value);
|
||||
} else {
|
||||
REQUIRE(*data == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Set a value in a 64 bit frame") {
|
||||
size_t rows = 10;
|
||||
size_t cols = 10;
|
||||
size_t bitdepth = 64;
|
||||
|
||||
Frame frame(rows, cols, Dtype::from_bitdepth(bitdepth));
|
||||
|
||||
// set a value
|
||||
uint64_t value = 255;
|
||||
frame.set(5, 7, value);
|
||||
|
||||
// only the value we did set should be non-zero
|
||||
for (size_t i = 0; i < rows; i++) {
|
||||
for (size_t j = 0; j < cols; j++) {
|
||||
uint64_t *data = (uint64_t *)frame.get(i, j);
|
||||
REQUIRE(data != nullptr);
|
||||
if (i == 5 && j == 7) {
|
||||
REQUIRE(*data == value);
|
||||
} else {
|
||||
REQUIRE(*data == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Move construct a frame") {
|
||||
size_t rows = 10;
|
||||
size_t cols = 10;
|
||||
size_t bitdepth = 8;
|
||||
|
||||
Frame frame(rows, cols, Dtype::from_bitdepth(bitdepth));
|
||||
std::byte *data = frame.data();
|
||||
|
||||
Frame frame2(std::move(frame));
|
||||
|
||||
// state of the moved from object
|
||||
REQUIRE(frame.rows() == 0);
|
||||
REQUIRE(frame.cols() == 0);
|
||||
REQUIRE(frame.dtype() == Dtype(Dtype::TypeIndex::ERROR));
|
||||
REQUIRE(frame.data() == nullptr);
|
||||
|
||||
// state of the moved to object
|
||||
REQUIRE(frame2.rows() == rows);
|
||||
REQUIRE(frame2.cols() == cols);
|
||||
REQUIRE(frame2.bitdepth() == bitdepth);
|
||||
REQUIRE(frame2.bytes() == rows * cols * bitdepth / 8);
|
||||
REQUIRE(frame2.data() == data);
|
||||
}
|
||||
|
||||
TEST_CASE("Move assign a frame") {
|
||||
size_t rows = 10;
|
||||
size_t cols = 10;
|
||||
size_t bitdepth = 8;
|
||||
|
||||
Frame frame(rows, cols, Dtype::from_bitdepth(bitdepth));
|
||||
std::byte *data = frame.data();
|
||||
|
||||
Frame frame2(5, 5, Dtype::from_bitdepth(16));
|
||||
|
||||
frame2 = std::move(frame);
|
||||
|
||||
// state of the moved from object
|
||||
REQUIRE(frame.rows() == 0);
|
||||
REQUIRE(frame.cols() == 0);
|
||||
REQUIRE(frame.dtype() == Dtype(Dtype::TypeIndex::ERROR));
|
||||
REQUIRE(frame.data() == nullptr);
|
||||
|
||||
// state of the moved to object
|
||||
REQUIRE(frame2.rows() == rows);
|
||||
REQUIRE(frame2.cols() == cols);
|
||||
REQUIRE(frame2.bitdepth() == bitdepth);
|
||||
REQUIRE(frame2.bytes() == rows * cols * bitdepth / 8);
|
||||
REQUIRE(frame2.data() == data);
|
||||
}
|
||||
|
||||
TEST_CASE("test explicit copy constructor") {
|
||||
size_t rows = 10;
|
||||
size_t cols = 10;
|
||||
size_t bitdepth = 8;
|
||||
|
||||
Frame frame(rows, cols, Dtype::from_bitdepth(bitdepth));
|
||||
std::byte *data = frame.data();
|
||||
|
||||
Frame frame2 = frame.copy();
|
||||
|
||||
// state of the original object
|
||||
REQUIRE(frame.rows() == rows);
|
||||
REQUIRE(frame.cols() == cols);
|
||||
REQUIRE(frame.bitdepth() == bitdepth);
|
||||
REQUIRE(frame.bytes() == rows * cols * bitdepth / 8);
|
||||
REQUIRE(frame.data() == data);
|
||||
|
||||
// state of the copied object
|
||||
REQUIRE(frame2.rows() == rows);
|
||||
REQUIRE(frame2.cols() == cols);
|
||||
REQUIRE(frame2.bitdepth() == bitdepth);
|
||||
REQUIRE(frame2.bytes() == rows * cols * bitdepth / 8);
|
||||
REQUIRE(frame2.data() != data);
|
||||
}
|
377
src/NDArray.test.cpp
Normal file
377
src/NDArray.test.cpp
Normal file
@ -0,0 +1,377 @@
|
||||
#include "aare/NDArray.hpp"
|
||||
#include <array>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
using aare::NDArray;
|
||||
using aare::NDView;
|
||||
using aare::Shape;
|
||||
|
||||
TEST_CASE("Initial size is zero if no size is specified") {
|
||||
NDArray<double> a;
|
||||
REQUIRE(a.size() == 0);
|
||||
REQUIRE(a.shape() == Shape<2>{0, 0});
|
||||
}
|
||||
|
||||
TEST_CASE("Construct from a DataSpan") {
|
||||
std::vector<int> some_data(9, 42);
|
||||
NDView<int, 2> view(some_data.data(), Shape<2>{3, 3});
|
||||
|
||||
NDArray<int, 2> image(view);
|
||||
|
||||
REQUIRE(image.shape() == view.shape());
|
||||
REQUIRE(image.size() == view.size());
|
||||
REQUIRE(image.data() != view.data());
|
||||
|
||||
for (uint32_t i = 0; i < image.size(); ++i) {
|
||||
REQUIRE(image(i) == view(i));
|
||||
}
|
||||
|
||||
// Changing the image doesn't change the view
|
||||
image = 43;
|
||||
for (uint32_t i = 0; i < image.size(); ++i) {
|
||||
REQUIRE(image(i) != view(i));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("1D image") {
|
||||
std::array<int64_t, 1> shape{{20}};
|
||||
NDArray<short, 1> img(shape, 3);
|
||||
REQUIRE(img.size() == 20);
|
||||
REQUIRE(img(5) == 3);
|
||||
}
|
||||
|
||||
TEST_CASE("Accessing a const object") {
|
||||
const NDArray<double, 3> img({3, 4, 5}, 0);
|
||||
REQUIRE(img(1, 1, 1) == 0);
|
||||
REQUIRE(img.size() == 3 * 4 * 5);
|
||||
REQUIRE(img.shape() == Shape<3>{3, 4, 5});
|
||||
REQUIRE(img.shape(0) == 3);
|
||||
REQUIRE(img.shape(1) == 4);
|
||||
REQUIRE(img.shape(2) == 5);
|
||||
}
|
||||
|
||||
TEST_CASE("Indexing of a 2D image") {
|
||||
std::array<int64_t, 2> shape{{3, 7}};
|
||||
NDArray<long> img(shape, 5);
|
||||
for (uint32_t i = 0; i != img.size(); ++i) {
|
||||
REQUIRE(img(i) == 5);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i != img.size(); ++i) {
|
||||
img(i) = i;
|
||||
}
|
||||
REQUIRE(img(0, 0) == 0);
|
||||
REQUIRE(img(0, 1) == 1);
|
||||
REQUIRE(img(1, 0) == 7);
|
||||
}
|
||||
|
||||
TEST_CASE("Indexing of a 3D image") {
|
||||
NDArray<float, 3> img{{{3, 4, 2}}, 5.0f};
|
||||
for (uint32_t i = 0; i != img.size(); ++i) {
|
||||
REQUIRE(img(i) == 5.0f);
|
||||
}
|
||||
|
||||
// Double check general properties
|
||||
REQUIRE(img.size() == 3 * 4 * 2);
|
||||
|
||||
for (uint32_t i = 0; i != img.size(); ++i) {
|
||||
img(i) = float(i);
|
||||
}
|
||||
REQUIRE(img(0, 0, 0) == 0);
|
||||
REQUIRE(img(0, 0, 1) == 1);
|
||||
REQUIRE(img(0, 1, 1) == 3);
|
||||
REQUIRE(img(1, 2, 0) == 12);
|
||||
REQUIRE(img(2, 3, 1) == 23);
|
||||
}
|
||||
|
||||
TEST_CASE("Divide double by int") {
|
||||
NDArray<double, 1> a{{5}, 5};
|
||||
NDArray<int, 1> b{{5}, 5};
|
||||
a /= b;
|
||||
for (auto it : a) {
|
||||
REQUIRE(it == 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Elementwise multiplication of 3D image") {
|
||||
std::array<int64_t, 3> shape{3, 4, 2};
|
||||
NDArray<double, 3> a{shape};
|
||||
NDArray<double, 3> b{shape};
|
||||
for (uint32_t i = 0; i != a.size(); ++i) {
|
||||
a(i) = i;
|
||||
b(i) = i;
|
||||
}
|
||||
auto c = a * b;
|
||||
REQUIRE(c(0, 0, 0) == 0 * 0);
|
||||
REQUIRE(c(0, 0, 1) == 1 * 1);
|
||||
REQUIRE(c(0, 1, 1) == 3 * 3);
|
||||
REQUIRE(c(1, 2, 0) == 12 * 12);
|
||||
REQUIRE(c(2, 3, 1) == 23 * 23);
|
||||
}
|
||||
|
||||
TEST_CASE("Compare two images") {
|
||||
NDArray<int> a;
|
||||
NDArray<int> b;
|
||||
CHECK((a == b));
|
||||
|
||||
a = NDArray<int>{{5, 10}, 0};
|
||||
CHECK((a != b));
|
||||
|
||||
b = NDArray<int>{{5, 10}, 0};
|
||||
CHECK((a == b));
|
||||
|
||||
b(3, 3) = 7;
|
||||
CHECK((a != b));
|
||||
}
|
||||
|
||||
TEST_CASE("Size and shape matches") {
|
||||
int64_t w = 15;
|
||||
int64_t h = 75;
|
||||
std::array<int64_t, 2> shape{w, h};
|
||||
NDArray<double> a{shape};
|
||||
REQUIRE(a.size() == static_cast<uint64_t>(w * h));
|
||||
REQUIRE(a.shape() == shape);
|
||||
}
|
||||
|
||||
TEST_CASE("Initial value matches for all elements") {
|
||||
double v = 4.35;
|
||||
NDArray<double> a{{5, 5}, v};
|
||||
for (uint32_t i = 0; i < a.size(); ++i) {
|
||||
REQUIRE(a(i) == v);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Data layout of 3D image, fast index last") {
|
||||
NDArray<int, 3> a{{3, 3, 3}, 0};
|
||||
REQUIRE(a.size() == 27);
|
||||
int *ptr = a.data();
|
||||
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
*ptr++ = 10 + i;
|
||||
REQUIRE(a(0, 0, i) == 10 + i);
|
||||
REQUIRE(a(i) == 10 + i);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Bitwise and on data") {
|
||||
|
||||
NDArray<uint16_t, 1> a({3}, 0);
|
||||
uint16_t mask = 0x3FF;
|
||||
a(0) = 16684;
|
||||
a(1) = 33068;
|
||||
a(2) = 52608;
|
||||
|
||||
a &= mask;
|
||||
|
||||
REQUIRE(a(0) == 300);
|
||||
REQUIRE(a(1) == 300);
|
||||
REQUIRE(a(2) == 384);
|
||||
}
|
||||
|
||||
// TEST_CASE("Benchmarks")
|
||||
// {
|
||||
// NDArray<double> img;
|
||||
// std::array<int64_t, 2> shape{ 512, 1024 };
|
||||
// BENCHMARK("Allocate 500k double image")
|
||||
// {
|
||||
// NDArray<double>im{ shape };
|
||||
// }
|
||||
// BENCHMARK("Allocate 500k double image with initial value")
|
||||
// {
|
||||
// NDArray<double>im{ shape, 3.14 };
|
||||
// }
|
||||
|
||||
// NDArray<double> a{ shape, 1.2 };
|
||||
// NDArray<double> b{ shape, 53. };
|
||||
// auto c = a + b;
|
||||
// c = a * b;
|
||||
// BENCHMARK("Multiply two images")
|
||||
// {
|
||||
// c = a * b;
|
||||
// }
|
||||
// BENCHMARK("Divide two images")
|
||||
// {
|
||||
// c = a / b;
|
||||
// }
|
||||
// BENCHMARK("Add two images")
|
||||
// {
|
||||
// c = a + b;
|
||||
// }
|
||||
// BENCHMARK("Subtract two images")
|
||||
// {
|
||||
// c = a - b;
|
||||
// }
|
||||
// }
|
||||
|
||||
TEST_CASE("Elementwise operatios on images") {
|
||||
std::array<int64_t, 2> shape{5, 5};
|
||||
double a_val = 3.0;
|
||||
double b_val = 8.0;
|
||||
|
||||
SECTION("Add two images") {
|
||||
NDArray<double> A(shape, a_val);
|
||||
NDArray<double> B(shape, b_val);
|
||||
|
||||
auto C = A + B;
|
||||
|
||||
// Value of C matches
|
||||
for (uint32_t i = 0; i < C.size(); ++i) {
|
||||
REQUIRE(C(i) == a_val + b_val);
|
||||
}
|
||||
|
||||
// Value of A is not changed
|
||||
for (uint32_t i = 0; i < A.size(); ++i) {
|
||||
REQUIRE(A(i) == a_val);
|
||||
}
|
||||
|
||||
// Value of B is not changed
|
||||
for (uint32_t i = 0; i < B.size(); ++i) {
|
||||
REQUIRE(B(i) == b_val);
|
||||
}
|
||||
|
||||
// A, B and C referes to different data
|
||||
REQUIRE(A.data() != B.data());
|
||||
REQUIRE(B.data() != C.data());
|
||||
}
|
||||
SECTION("Subtract two images") {
|
||||
NDArray<double> A(shape, a_val);
|
||||
NDArray<double> B(shape, b_val);
|
||||
auto C = A - B;
|
||||
|
||||
// Value of C matches
|
||||
for (uint32_t i = 0; i < C.size(); ++i) {
|
||||
REQUIRE(C(i) == a_val - b_val);
|
||||
}
|
||||
|
||||
// Value of A is not changed
|
||||
for (uint32_t i = 0; i < A.size(); ++i) {
|
||||
REQUIRE(A(i) == a_val);
|
||||
}
|
||||
|
||||
// Value of B is not changed
|
||||
for (uint32_t i = 0; i < B.size(); ++i) {
|
||||
REQUIRE(B(i) == b_val);
|
||||
}
|
||||
|
||||
// A, B and C referes to different data
|
||||
REQUIRE(A.data() != B.data());
|
||||
REQUIRE(B.data() != C.data());
|
||||
}
|
||||
SECTION("Multiply two images") {
|
||||
NDArray<double> A(shape, a_val);
|
||||
NDArray<double> B(shape, b_val);
|
||||
auto C = A * B;
|
||||
|
||||
// Value of C matches
|
||||
for (uint32_t i = 0; i < C.size(); ++i) {
|
||||
REQUIRE(C(i) == a_val * b_val);
|
||||
}
|
||||
|
||||
// Value of A is not changed
|
||||
for (uint32_t i = 0; i < A.size(); ++i) {
|
||||
REQUIRE(A(i) == a_val);
|
||||
}
|
||||
|
||||
// Value of B is not changed
|
||||
for (uint32_t i = 0; i < B.size(); ++i) {
|
||||
REQUIRE(B(i) == b_val);
|
||||
}
|
||||
|
||||
// A, B and C referes to different data
|
||||
REQUIRE(A.data() != B.data());
|
||||
REQUIRE(B.data() != C.data());
|
||||
}
|
||||
SECTION("Divide two images") {
|
||||
NDArray<double> A(shape, a_val);
|
||||
NDArray<double> B(shape, b_val);
|
||||
auto C = A / B;
|
||||
|
||||
// Value of C matches
|
||||
for (uint32_t i = 0; i < C.size(); ++i) {
|
||||
REQUIRE(C(i) == a_val / b_val);
|
||||
}
|
||||
|
||||
// Value of A is not changed
|
||||
for (uint32_t i = 0; i < A.size(); ++i) {
|
||||
REQUIRE(A(i) == a_val);
|
||||
}
|
||||
|
||||
// Value of B is not changed
|
||||
for (uint32_t i = 0; i < B.size(); ++i) {
|
||||
REQUIRE(B(i) == b_val);
|
||||
}
|
||||
|
||||
// A, B and C referes to different data
|
||||
REQUIRE(A.data() != B.data());
|
||||
REQUIRE(B.data() != C.data());
|
||||
}
|
||||
|
||||
SECTION("subtract scalar") {
|
||||
NDArray<double> A(shape, a_val);
|
||||
NDArray<double> B(shape, b_val);
|
||||
double v = 1.0;
|
||||
auto C = A - v;
|
||||
REQUIRE(C.data() != A.data());
|
||||
|
||||
// Value of C matches
|
||||
for (uint32_t i = 0; i < C.size(); ++i) {
|
||||
REQUIRE(C(i) == a_val - v);
|
||||
}
|
||||
|
||||
// Value of A is not changed
|
||||
for (uint32_t i = 0; i < A.size(); ++i) {
|
||||
REQUIRE(A(i) == a_val);
|
||||
}
|
||||
}
|
||||
SECTION("add scalar") {
|
||||
NDArray<double> A(shape, a_val);
|
||||
NDArray<double> B(shape, b_val);
|
||||
double v = 1.0;
|
||||
auto C = A + v;
|
||||
REQUIRE(C.data() != A.data());
|
||||
|
||||
// Value of C matches
|
||||
for (uint32_t i = 0; i < C.size(); ++i) {
|
||||
REQUIRE(C(i) == a_val + v);
|
||||
}
|
||||
|
||||
// Value of A is not changed
|
||||
for (uint32_t i = 0; i < A.size(); ++i) {
|
||||
REQUIRE(A(i) == a_val);
|
||||
}
|
||||
}
|
||||
SECTION("divide with scalar") {
|
||||
NDArray<double> A(shape, a_val);
|
||||
NDArray<double> B(shape, b_val);
|
||||
double v = 3.7;
|
||||
auto C = A / v;
|
||||
REQUIRE(C.data() != A.data());
|
||||
|
||||
// Value of C matches
|
||||
for (uint32_t i = 0; i < C.size(); ++i) {
|
||||
REQUIRE(C(i) == a_val / v);
|
||||
}
|
||||
|
||||
// Value of A is not changed
|
||||
for (uint32_t i = 0; i < A.size(); ++i) {
|
||||
REQUIRE(A(i) == a_val);
|
||||
}
|
||||
}
|
||||
SECTION("multiply with scalar") {
|
||||
NDArray<double> A(shape, a_val);
|
||||
NDArray<double> B(shape, b_val);
|
||||
double v = 3.7;
|
||||
auto C = A / v;
|
||||
REQUIRE(C.data() != A.data());
|
||||
|
||||
// Value of C matches
|
||||
for (uint32_t i = 0; i < C.size(); ++i) {
|
||||
REQUIRE(C(i) == a_val / v);
|
||||
}
|
||||
|
||||
// Value of A is not changed
|
||||
for (uint32_t i = 0; i < A.size(); ++i) {
|
||||
REQUIRE(A(i) == a_val);
|
||||
}
|
||||
}
|
||||
}
|
193
src/NDView.test.cpp
Normal file
193
src/NDView.test.cpp
Normal file
@ -0,0 +1,193 @@
|
||||
#include "aare/NDView.hpp"
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
using aare::NDView;
|
||||
using aare::Shape;
|
||||
|
||||
TEST_CASE("Element reference 1D") {
|
||||
std::vector<int> vec;
|
||||
for (int i = 0; i != 10; ++i) {
|
||||
vec.push_back(i);
|
||||
}
|
||||
NDView<int, 1> data(vec.data(), Shape<1>{10});
|
||||
REQUIRE(vec.size() == static_cast<size_t>(data.size()));
|
||||
for (int i = 0; i != 10; ++i) {
|
||||
REQUIRE(data(i) == vec[i]);
|
||||
REQUIRE(data[i] == vec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Element reference 2D") {
|
||||
std::vector<int> vec;
|
||||
for (int i = 0; i != 12; ++i) {
|
||||
vec.push_back(i);
|
||||
}
|
||||
|
||||
NDView<int, 2> data(vec.data(), Shape<2>{3, 4});
|
||||
REQUIRE(vec.size() == static_cast<size_t>(data.size()));
|
||||
int i = 0;
|
||||
for (int row = 0; row != 3; ++row) {
|
||||
for (int col = 0; col != 4; ++col) {
|
||||
REQUIRE(data(row, col) == i);
|
||||
REQUIRE(data[i] == vec[i]);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Element reference 3D") {
|
||||
std::vector<int> vec;
|
||||
for (int i = 0; i != 24; ++i) {
|
||||
vec.push_back(i);
|
||||
}
|
||||
NDView<int, 3> data(vec.data(), Shape<3>{2, 3, 4});
|
||||
REQUIRE(vec.size() == static_cast<size_t>(data.size()));
|
||||
int i = 0;
|
||||
for (int frame = 0; frame != 2; ++frame) {
|
||||
for (int row = 0; row != 3; ++row) {
|
||||
for (int col = 0; col != 4; ++col) {
|
||||
REQUIRE(data(frame, row, col) == i);
|
||||
REQUIRE(data[i] == vec[i]);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Plus and miuns with single value") {
|
||||
std::vector<int> vec;
|
||||
for (int i = 0; i != 12; ++i) {
|
||||
vec.push_back(i);
|
||||
}
|
||||
NDView<int, 2> data(vec.data(), Shape<2>{3, 4});
|
||||
data += 5;
|
||||
int i = 0;
|
||||
for (int row = 0; row != 3; ++row) {
|
||||
for (int col = 0; col != 4; ++col) {
|
||||
REQUIRE(data(row, col) == i + 5);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
data -= 3;
|
||||
i = 0;
|
||||
for (int row = 0; row != 3; ++row) {
|
||||
for (int col = 0; col != 4; ++col) {
|
||||
REQUIRE(data(row, col) == i + 2);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Multiply and divide with single value") {
|
||||
std::vector<int> vec;
|
||||
for (int i = 0; i != 12; ++i) {
|
||||
vec.push_back(i);
|
||||
}
|
||||
NDView<int, 2> data(vec.data(), Shape<2>{3, 4});
|
||||
data *= 5;
|
||||
int i = 0;
|
||||
for (int row = 0; row != 3; ++row) {
|
||||
for (int col = 0; col != 4; ++col) {
|
||||
REQUIRE(data(row, col) == i * 5);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
data /= 3;
|
||||
i = 0;
|
||||
for (int row = 0; row != 3; ++row) {
|
||||
for (int col = 0; col != 4; ++col) {
|
||||
REQUIRE(data(row, col) == (i * 5) / 3);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("elementwise assign") {
|
||||
std::vector<int> vec(25);
|
||||
NDView<int, 2> data(vec.data(), Shape<2>{5, 5});
|
||||
|
||||
data = 3;
|
||||
for (auto it : data) {
|
||||
REQUIRE(it == 3);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("iterators") {
|
||||
std::vector<int> vec;
|
||||
for (int i = 0; i != 12; ++i) {
|
||||
vec.push_back(i);
|
||||
}
|
||||
NDView<int, 1> data(vec.data(), Shape<1>{12});
|
||||
int i = 0;
|
||||
for (const auto item : data) {
|
||||
REQUIRE(item == vec[i]);
|
||||
++i;
|
||||
}
|
||||
REQUIRE(i == 12);
|
||||
|
||||
for (auto ptr = data.begin(); ptr != data.end(); ++ptr) {
|
||||
*ptr += 1;
|
||||
}
|
||||
for (auto &item : data) {
|
||||
++item;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (const auto item : data) {
|
||||
REQUIRE(item == i + 2);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
// TEST_CASE("shape from vector") {
|
||||
// std::vector<int> vec;
|
||||
// for (int i = 0; i != 12; ++i) {
|
||||
// vec.push_back(i);
|
||||
// }
|
||||
// std::vector<int64_t> shape{3, 4};
|
||||
// NDView<int, 2> data(vec.data(), shape);
|
||||
// }
|
||||
|
||||
TEST_CASE("divide with another span") {
|
||||
std::vector<int> vec0{9, 12, 3};
|
||||
std::vector<int> vec1{3, 2, 1};
|
||||
std::vector<int> result{3, 6, 3};
|
||||
|
||||
NDView<int, 1> data0(vec0.data(), Shape<1>{static_cast<int64_t>(vec0.size())});
|
||||
NDView<int, 1> data1(vec1.data(), Shape<1>{static_cast<int64_t>(vec1.size())});
|
||||
|
||||
data0 /= data1;
|
||||
|
||||
for (size_t i = 0; i != vec0.size(); ++i) {
|
||||
REQUIRE(data0[i] == result[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Retrieve shape") {
|
||||
std::vector<int> vec;
|
||||
for (int i = 0; i != 12; ++i) {
|
||||
vec.push_back(i);
|
||||
}
|
||||
NDView<int, 2> data(vec.data(), Shape<2>{3, 4});
|
||||
REQUIRE(data.shape()[0] == 3);
|
||||
REQUIRE(data.shape()[1] == 4);
|
||||
}
|
||||
|
||||
TEST_CASE("compare two views") {
|
||||
std::vector<int> vec1;
|
||||
for (int i = 0; i != 12; ++i) {
|
||||
vec1.push_back(i);
|
||||
}
|
||||
NDView<int, 2> view1(vec1.data(), Shape<2>{3, 4});
|
||||
|
||||
std::vector<int> vec2;
|
||||
for (int i = 0; i != 12; ++i) {
|
||||
vec2.push_back(i);
|
||||
}
|
||||
NDView<int, 2> view2(vec2.data(), Shape<2>{3, 4});
|
||||
|
||||
REQUIRE((view1 == view2));
|
||||
}
|
65
src/defs.cpp
Normal file
65
src/defs.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
#include "aare/defs.hpp"
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace aare {
|
||||
|
||||
/**
|
||||
* @brief Convert a DetectorType to a string
|
||||
* @param type DetectorType
|
||||
* @return string representation of the DetectorType
|
||||
*/
|
||||
template <> std::string toString(DetectorType arg) {
|
||||
switch (arg) {
|
||||
case DetectorType::Jungfrau:
|
||||
return "Jungfrau";
|
||||
case DetectorType::Eiger:
|
||||
return "Eiger";
|
||||
case DetectorType::Mythen3:
|
||||
return "Mythen3";
|
||||
case DetectorType::Moench:
|
||||
return "Moench";
|
||||
case DetectorType::ChipTestBoard:
|
||||
return "ChipTestBoard";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a string to a DetectorType
|
||||
* @param name string representation of the DetectorType
|
||||
* @return DetectorType
|
||||
* @throw runtime_error if the string does not match any DetectorType
|
||||
*/
|
||||
template <> DetectorType StringTo(const std::string &arg) {
|
||||
if (arg == "Jungfrau")
|
||||
return DetectorType::Jungfrau;
|
||||
if (arg == "Eiger")
|
||||
return DetectorType::Eiger;
|
||||
if (arg == "Mythen3")
|
||||
return DetectorType::Mythen3;
|
||||
if (arg == "Moench")
|
||||
return DetectorType::Moench;
|
||||
if (arg == "ChipTestBoard")
|
||||
return DetectorType::ChipTestBoard;
|
||||
throw std::runtime_error("Could not decode dector from: \"" + arg + "\"");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a string to a TimingMode
|
||||
* @param mode string representation of the TimingMode
|
||||
* @return TimingMode
|
||||
* @throw runtime_error if the string does not match any TimingMode
|
||||
*/
|
||||
template <> TimingMode StringTo(const std::string &arg) {
|
||||
if (arg == "auto")
|
||||
return TimingMode::Auto;
|
||||
if (arg == "trigger")
|
||||
return TimingMode::Trigger;
|
||||
throw std::runtime_error("Could not decode timing mode from: \"" + arg + "\"");
|
||||
}
|
||||
|
||||
// template <> TimingMode StringTo<TimingMode>(std::string mode);
|
||||
|
||||
} // namespace aare
|
42
src/defs.test.cpp
Normal file
42
src/defs.test.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
#include "aare/defs.hpp"
|
||||
// #include "aare/utils/floats.hpp"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <string>
|
||||
TEST_CASE("Enum to string conversion") {
|
||||
// By the way I don't think the enum string conversions should be in the defs.hpp file
|
||||
// but let's use this to show a test
|
||||
REQUIRE(toString(aare::DetectorType::Jungfrau) == "Jungfrau");
|
||||
}
|
||||
|
||||
TEST_CASE("Cluster creation") {
|
||||
aare::Cluster c(13, 15);
|
||||
REQUIRE(c.cluster_sizeX == 13);
|
||||
REQUIRE(c.cluster_sizeY == 15);
|
||||
REQUIRE(c.dt == aare::Dtype(typeid(int32_t)));
|
||||
REQUIRE(c.data() != nullptr);
|
||||
|
||||
aare::Cluster c2(c);
|
||||
REQUIRE(c2.cluster_sizeX == 13);
|
||||
REQUIRE(c2.cluster_sizeY == 15);
|
||||
REQUIRE(c2.dt == aare::Dtype(typeid(int32_t)));
|
||||
REQUIRE(c2.data() != nullptr);
|
||||
}
|
||||
|
||||
// TEST_CASE("cluster set and get data") {
|
||||
|
||||
// aare::Cluster c2(33, 44, aare::Dtype(typeid(double)));
|
||||
// REQUIRE(c2.cluster_sizeX == 33);
|
||||
// REQUIRE(c2.cluster_sizeY == 44);
|
||||
// REQUIRE(c2.dt == aare::Dtype::DOUBLE);
|
||||
// double v = 3.14;
|
||||
// c2.set<double>(0, v);
|
||||
// double v2 = c2.get<double>(0);
|
||||
// REQUIRE(aare::compare_floats<double>(v, v2));
|
||||
|
||||
// c2.set<double>(33 * 44 - 1, 123.11);
|
||||
// double v3 = c2.get<double>(33 * 44 - 1);
|
||||
// REQUIRE(aare::compare_floats<double>(123.11, v3));
|
||||
|
||||
// REQUIRE_THROWS_AS(c2.set(0, 1), std::invalid_argument); // set int to double
|
||||
// }
|
Reference in New Issue
Block a user