clang-format
Some checks failed
Build on RHEL8 / build (push) Successful in 2m30s
Build on RHEL9 / build (push) Successful in 2m34s
Run tests using data on local RHEL8 / build (push) Failing after 3m10s

This commit is contained in:
2026-02-19 15:35:19 +01:00
parent 1f7a87cc30
commit 5dbc746462
34 changed files with 327 additions and 350 deletions

View File

@@ -378,7 +378,9 @@ ClusterFile<ClusterType, Enable>::read_frame_without_cut() {
else if (ferror(fp))
throw std::runtime_error(LOCATION + "Error reading from file");
throw std::runtime_error(LOCATION + "Unexpected error (not feof or ferror) when reading frame number");
throw std::runtime_error(
LOCATION +
"Unexpected error (not feof or ferror) when reading frame number");
}
int32_t n_clusters; // Saved as 32bit integer in the cluster file

View File

@@ -40,7 +40,8 @@ struct FileConfig {
// ", cols: " + std::to_string(cols) +
// ", geometry: " + geometry.to_string() +
// ", detector_type: " + ToString(detector_type) +
// ", max_frames_per_file: " + std::to_string(max_frames_per_file) +
// ", max_frames_per_file: " +
// std::to_string(max_frames_per_file) +
// ", total_frames: " + std::to_string(total_frames) + " }";
// }
};

View File

@@ -36,7 +36,7 @@ class NDArray : public ArrayExpr<NDArray<T, Ndim>, Ndim> {
* @brief Default constructor. Constructs an empty NDArray.
*
*/
NDArray() : shape_(), strides_(c_strides<Ndim>(shape_)), data_(nullptr) {};
NDArray() : shape_(), strides_(c_strides<Ndim>(shape_)), data_(nullptr){};
/**
* @brief Construct a new NDArray object with a given shape.

View File

@@ -27,15 +27,14 @@ Shape<Ndim> make_shape(const std::vector<size_t> &shape) {
return arr;
}
/**
* @brief Helper function to drop the first dimension of a shape.
* This is useful when you want to create a 2D view from a 3D array.
* @param shape The shape to drop the first dimension from.
* @return A new shape with the first dimension dropped.
*/
template<size_t Ndim>
Shape<Ndim-1> drop_first_dim(const Shape<Ndim> &shape) {
template <size_t Ndim>
Shape<Ndim - 1> drop_first_dim(const Shape<Ndim> &shape) {
static_assert(Ndim > 1, "Cannot drop first dimension from a 1D shape");
Shape<Ndim - 1> new_shape;
std::copy(shape.begin() + 1, shape.end(), new_shape.begin());
@@ -43,13 +42,12 @@ Shape<Ndim-1> drop_first_dim(const Shape<Ndim> &shape) {
}
/**
* @brief Helper function when constructing NDArray/NDView. Calculates the number
* of elements in the resulting array from a shape.
* @brief Helper function when constructing NDArray/NDView. Calculates the
* number of elements in the resulting array from a shape.
* @param shape The shape to calculate the number of elements for.
* @return The number of elements in and NDArray/NDView of that shape.
*/
template <size_t Ndim>
size_t num_elements(const Shape<Ndim> &shape) {
template <size_t Ndim> size_t num_elements(const Shape<Ndim> &shape) {
return std::accumulate(shape.begin(), shape.end(), 1,
std::multiplies<size_t>());
}
@@ -94,28 +92,28 @@ class NDView : public ArrayExpr<NDView<T, Ndim>, Ndim> {
: buffer_(buffer), strides_(c_strides<Ndim>(shape)), shape_(shape),
size_(std::accumulate(std::begin(shape), std::end(shape), 1,
std::multiplies<>())) {}
template <typename... Ix>
std::enable_if_t<sizeof...(Ix) == Ndim, T &> operator()(Ix... index) {
return buffer_[element_offset(strides_, index...)];
}
template <typename... Ix>
std::enable_if_t<sizeof...(Ix) == 1 && (Ndim > 1), NDView<T, Ndim - 1>> operator()(Ix... index) {
std::enable_if_t<sizeof...(Ix) == 1 && (Ndim > 1), NDView<T, Ndim - 1>>
operator()(Ix... index) {
// return a view of the next dimension
std::array<ssize_t, Ndim - 1> new_shape{};
std::copy_n(shape_.begin() + 1, Ndim - 1, new_shape.begin());
return NDView<T, Ndim - 1>(&buffer_[element_offset(strides_, index...)],
new_shape);
}
template <typename... Ix>
std::enable_if_t<sizeof...(Ix) == Ndim, const T &> operator()(Ix... index) const {
std::enable_if_t<sizeof...(Ix) == Ndim, const T &>
operator()(Ix... index) const {
return buffer_[element_offset(strides_, index...)];
}
ssize_t size() const { return static_cast<ssize_t>(size_); }
size_t total_bytes() const { return size_ * sizeof(T); }
std::array<ssize_t, Ndim> strides() const noexcept { return strides_; }
@@ -124,15 +122,11 @@ class NDView : public ArrayExpr<NDView<T, Ndim>, Ndim> {
T *end() { return buffer_ + size_; }
T const *begin() const { return buffer_; }
T const *end() const { return buffer_ + size_; }
/**
* @brief Access element at index i.
*/
T &operator[](ssize_t i) { return buffer_[i]; }
T &operator[](ssize_t i) { return buffer_[i]; }
/**
* @brief Access element at index i.
@@ -207,7 +201,7 @@ class NDView : public ArrayExpr<NDView<T, Ndim>, Ndim> {
void print_all() const;
/**
* @brief Create a subview of a range of the first dimension.
* @brief Create a subview of a range of the first dimension.
* This is useful for splitting a batches of frames in parallel processing.
* @param first The first index of the subview (inclusive).
* @param last The last index of the subview (exclusive).

View File

@@ -27,8 +27,8 @@
#include <atomic>
#include <cassert>
#include <cstdlib>
#include <cstddef>
#include <cstdlib>
#include <memory>
#include <stdexcept>
#include <type_traits>

View File

@@ -49,7 +49,6 @@ class RawFile : public FileInterface {
Frame read_frame(size_t frame_number) override;
std::vector<Frame> read_n(size_t n_frames) override;
/**
* @brief Read one ROI defined in the master file
* @param roi_index index of the ROI to read
@@ -63,7 +62,7 @@ class RawFile : public FileInterface {
* @brief Read all ROIs defined in the master file
* @return vector of Frames (one Frame per ROI)
*/
std::vector<Frame>read_rois();
std::vector<Frame> read_rois();
/**
* @brief Read n frames for the given ROI index
@@ -72,7 +71,7 @@ class RawFile : public FileInterface {
* @return vector of Frames
*/
std::vector<Frame> read_n_with_roi(const size_t n_frames,
const size_t roi_index);
const size_t roi_index);
void read_into(std::byte *image_buf) override;
void read_into(std::byte *image_buf, size_t n_frames) override;

View File

@@ -175,11 +175,9 @@ calculate_pedestal(NDView<uint16_t, 3> raw_data, ssize_t n_threads) {
count += cnt;
}
// Will move to a NDArray<T, 3 - static_cast<ssize_t>(only_gain0)>
// if only_gain0 is true
return safe_divide<T>(accumulator, count);
}
/**

View File

@@ -6,12 +6,11 @@
#include <vector>
namespace aare {
uint16_t adc_sar_05_06_07_08decode64to16(uint64_t input);
uint16_t adc_sar_05_decode64to16(uint64_t input);
uint16_t adc_sar_04_decode64to16(uint64_t input);
void adc_sar_05_06_07_08decode64to16(NDView<uint64_t, 2> input,
NDView<uint16_t, 2> output);
NDView<uint16_t, 2> output);
void adc_sar_05_decode64to16(NDView<uint64_t, 2> input,
NDView<uint16_t, 2> output);
void adc_sar_04_decode64to16(NDView<uint64_t, 2> input,
@@ -22,19 +21,22 @@ void adc_sar_04_decode64to16(NDView<uint64_t, 2> input,
* and then return the lower 24 bits as an 32 bit integer
* @param input 32-ibt input value
* @param offset (should be in range 0-7 to allow for full 24 bits)
* @return uint32_t
* @return uint32_t
*/
uint32_t mask32to24bits(uint32_t input, BitOffset offset={});
uint32_t mask32to24bits(uint32_t input, BitOffset offset = {});
/**
* @brief Expand 24 bit values in a 8bit buffer to 32bit unsigned integers
* Used for detectors with 24bit counters in combination with CTB
*
* @param input View of the 24 bit data as uint8_t (no 24bit native data type exists)
* @param output Destination of the expanded data (32bit, unsigned)
* @param offset Offset within the first byte to where the data starts (0-7 bits)
*
* @param input View of the 24 bit data as uint8_t (no 24bit native data type
* exists)
* @param output Destination of the expanded data (32bit, unsigned)
* @param offset Offset within the first byte to where the data starts (0-7
* bits)
*/
void expand24to32bit(NDView<uint8_t,1> input, NDView<uint32_t,1> output, BitOffset offset={});
void expand24to32bit(NDView<uint8_t, 1> input, NDView<uint32_t, 1> output,
BitOffset offset = {});
/**
* @brief Apply custom weights to a 16-bit input value. Will sum up

View File

@@ -353,16 +353,15 @@ using DataTypeVariants = std::variant<uint16_t, uint32_t>;
constexpr uint16_t ADC_MASK =
0x3FFF; // used to mask out the gain bits in Jungfrau
class BitOffset{
class BitOffset {
uint8_t m_offset{};
public:
public:
BitOffset() = default;
explicit BitOffset(uint32_t offset);
uint8_t value() const {return m_offset;}
bool operator==(const BitOffset& other) const;
bool operator<(const BitOffset& other) const;
uint8_t value() const { return m_offset; }
bool operator==(const BitOffset &other) const;
bool operator<(const BitOffset &other) const;
};
} // namespace aare

View File

@@ -106,8 +106,8 @@ class Logger {
}
std::ostringstream &Get() {
os << Color(m_level) << "- " << Timestamp() << " " << Logger::ToString(m_level)
<< ": ";
os << Color(m_level) << "- " << Timestamp() << " "
<< Logger::ToString(m_level) << ": ";
return os;
}

View File

@@ -20,9 +20,8 @@ void RunInParallel(F func, const std::vector<std::pair<int, int>> &tasks) {
}
}
template <typename T>
std::vector<NDView<T,3>> make_subviews(NDView<T, 3> &data, ssize_t n_threads) {
std::vector<NDView<T, 3>> make_subviews(NDView<T, 3> &data, ssize_t n_threads) {
std::vector<NDView<T, 3>> subviews;
subviews.reserve(n_threads);
auto limits = split_task(0, data.shape(0), n_threads);

View File

@@ -39,7 +39,8 @@ void define_raw_file_io_bindings(py::module &m) {
// return headers from all subfiles
py::array_t<DetectorHeader> header(self.n_modules());
py::array image = allocate_image_data(self.bytes_per_pixel(), shape);
py::array image =
allocate_image_data(self.bytes_per_pixel(), shape);
self.read_into(
reinterpret_cast<std::byte *>(image.mutable_data()),
header.mutable_data());
@@ -72,7 +73,8 @@ void define_raw_file_io_bindings(py::module &m) {
{self.n_modules_in_roi()[0], n_frames});
}
py::array images = allocate_image_data(self.bytes_per_pixel(), shape);
py::array images =
allocate_image_data(self.bytes_per_pixel(), shape);
self.read_into(
reinterpret_cast<std::byte *>(images.mutable_data()),
n_frames, header.mutable_data());
@@ -85,33 +87,32 @@ void define_raw_file_io_bindings(py::module &m) {
.def(
"read_roi",
[](RawFile &self,
const size_t roi_index) {
[](RawFile &self, const size_t roi_index) {
if (self.num_rois() == 0) {
throw std::runtime_error(LOCATION + "No ROIs defined.");
}
if ( roi_index >= self.num_rois()) {
if (roi_index >= self.num_rois()) {
throw std::runtime_error(LOCATION +
"ROI index out of range.");
}
// return headers from all subfiles
py::array_t<DetectorHeader> header(self.n_modules_in_roi()[roi_index]);
py::array_t<DetectorHeader> header(
self.n_modules_in_roi()[roi_index]);
std::vector<size_t> shape;
shape.reserve(2);
shape.push_back(self.roi_geometries(roi_index).pixels_y());
shape.push_back(self.roi_geometries(roi_index).pixels_x());
py::array image = allocate_image_data(self.bytes_per_pixel(), shape);
py::array image =
allocate_image_data(self.bytes_per_pixel(), shape);
self.read_roi_into(
reinterpret_cast<std::byte *>(image.mutable_data()),
roi_index, self.tell(), header.mutable_data());
self.seek(self.tell() + 1); // advance frame number so the
return py::make_tuple(header, image);
},
@@ -143,8 +144,6 @@ void define_raw_file_io_bindings(py::module &m) {
throw std::runtime_error(LOCATION + "No ROIs defined.");
}
size_t number_of_ROIs = self.num_rois();
// const uint8_t item_size = self.bytes_per_pixel();
@@ -152,25 +151,25 @@ void define_raw_file_io_bindings(py::module &m) {
std::vector<py::array> images(number_of_ROIs);
// return headers from all subfiles
std::vector<py::array_t<DetectorHeader>> headers(number_of_ROIs);
std::vector<py::array_t<DetectorHeader>> headers(
number_of_ROIs);
for (size_t r = 0; r < number_of_ROIs; r++) {
headers[r] =
py::array_t<DetectorHeader>(self.n_modules_in_roi()[r]);
}
for (size_t r = 0; r < number_of_ROIs; r++) {
std::vector<size_t> shape;
shape.reserve(2);
shape.push_back(self.roi_geometries(r).pixels_y());
shape.push_back(self.roi_geometries(r).pixels_x());
images[r] = allocate_image_data(self.bytes_per_pixel(), shape);
images[r] =
allocate_image_data(self.bytes_per_pixel(), shape);
self.read_roi_into(
reinterpret_cast<std::byte *>(images[r].mutable_data()),
r, self.tell(),headers[r].mutable_data());
r, self.tell(), headers[r].mutable_data());
}
self.seek(self.tell() + 1); // advance frame number so the
return py::make_tuple(headers, images);
@@ -217,12 +216,10 @@ void define_raw_file_io_bindings(py::module &m) {
// return headers from all subfiles
auto n_mod = self.n_modules_in_roi()[roi_index];
py::array_t<DetectorHeader> header({
n_frames, n_mod}
);
py::array_t<DetectorHeader> header({n_frames, n_mod});
py::array images = allocate_image_data(self.bytes_per_pixel(), shape);
py::array images =
allocate_image_data(self.bytes_per_pixel(), shape);
auto image_buffer =
reinterpret_cast<std::byte *>(images.mutable_data());

View File

@@ -50,7 +50,7 @@ void define_ctb_raw_file_io_bindings(py::module &m) {
return output;
});
m.def("adc_sar_05_decode64to16", [](py::array_t<uint8_t> input) {
if (input.ndim() != 2) {
throw std::runtime_error(
@@ -121,67 +121,65 @@ void define_ctb_raw_file_io_bindings(py::module &m) {
});
m.def("expand24to32bit",
[](py::array_t<uint8_t, py::array::c_style | py::array::forcecast>
&input, uint32_t offset){
[](py::array_t<uint8_t, py::array::c_style | py::array::forcecast>
&input,
uint32_t offset) {
aare::BitOffset bitoff(offset);
py::buffer_info buf = input.request();
aare::BitOffset bitoff(offset);
py::buffer_info buf = input.request();
constexpr uint32_t bytes_per_channel = 3; // 24 bit
py::array_t<uint32_t> output(buf.size / bytes_per_channel);
constexpr uint32_t bytes_per_channel = 3; //24 bit
py::array_t<uint32_t> output(buf.size/bytes_per_channel);
NDView<uint8_t, 1> input_view(input.mutable_data(),
{input.size()});
NDView<uint32_t, 1> output_view(output.mutable_data(),
{output.size()});
NDView<uint8_t, 1> input_view(input.mutable_data(),
{input.size()});
NDView<uint32_t, 1> output_view(output.mutable_data(),
{output.size()});
aare::expand24to32bit(input_view, output_view, bitoff);
return output;
});
aare::expand24to32bit(input_view, output_view, bitoff);
return output;
});
m.def("decode_my302",
[](py::array_t<uint8_t, py::array::c_style | py::array::forcecast>
&input, uint32_t offset){
[](py::array_t<uint8_t, py::array::c_style | py::array::forcecast>
&input,
uint32_t offset) {
// Physical layout of the chip
constexpr size_t channels = 64;
constexpr size_t counters = 3;
constexpr size_t bytes_per_channel = 3; // 24 bit
constexpr int n_outputs = 2;
// Physical layout of the chip
constexpr size_t channels = 64;
constexpr size_t counters = 3;
constexpr size_t bytes_per_channel = 3; //24 bit
constexpr int n_outputs = 2;
ssize_t expected_size = channels * counters * bytes_per_channel;
ssize_t expected_size = channels*counters*bytes_per_channel;
// If whe have an offset we need one extra byte per output
aare::BitOffset bitoff(offset);
if (bitoff.value())
expected_size += n_outputs;
//If whe have an offset we need one extra byte per output
aare::BitOffset bitoff(offset);
if(bitoff.value())
expected_size += n_outputs;
if (input.size() != expected_size) {
throw std::runtime_error(fmt::format(
"{} Expected an input size of {} bytes. Called "
"with input size of {}",
LOCATION, expected_size, input.size()));
}
if (input.size() != expected_size) {
throw std::runtime_error(
fmt::format("{} Expected an input size of {} bytes. Called "
"with input size of {}",
LOCATION, expected_size, input.size()));
}
py::buffer_info buf = input.request();
py::array_t<uint32_t> output(channels * counters);
py::buffer_info buf = input.request();
py::array_t<uint32_t> output(channels * counters);
for (int i = 0; i != n_outputs; ++i) {
auto step = input.size() / n_outputs;
auto out_step = output.size() / n_outputs;
NDView<uint8_t, 1> input_view(input.mutable_data() + step * i,
{input.size() / n_outputs});
NDView<uint32_t, 1> output_view(output.mutable_data() +
out_step * i,
{output.size() / n_outputs});
for (int i = 0; i!=n_outputs; ++i){
auto step = input.size()/n_outputs;
auto out_step = output.size()/n_outputs;
NDView<uint8_t, 1> input_view(input.mutable_data()+step*i,
{input.size()/n_outputs});
NDView<uint32_t, 1> output_view(output.mutable_data()+out_step*i,
{output.size()/n_outputs});
aare::expand24to32bit(input_view, output_view, bitoff);
}
aare::expand24to32bit(input_view, output_view, bitoff);
}
return output;
});
return output;
});
py::class_<CtbRawFile>(m, "CtbRawFile")
.def(py::init<const std::filesystem::path &>())

View File

@@ -64,9 +64,8 @@ void define_file_io_bindings(py::module &m) {
.def_property_readonly("cols", &File::cols)
.def_property_readonly("bitdepth", &File::bitdepth)
.def_property_readonly("bytes_per_pixel", &File::bytes_per_pixel)
.def_property_readonly(
"detector_type",
[](File &self) { return self.detector_type(); })
.def_property_readonly("detector_type",
[](File &self) { return self.detector_type(); })
.def("read_frame",
[](File &self) {
const uint8_t item_size = self.bytes_per_pixel();
@@ -161,7 +160,6 @@ void define_file_io_bindings(py::module &m) {
}
});
py::class_<ScanParameters>(m, "ScanParameters")
.def(py::init<const std::string &>())
.def(py::init<const ScanParameters &>())

View File

@@ -86,17 +86,17 @@ struct fmt_format_trait<Cluster<T, ClusterSizeX, ClusterSizeY, CoordType>> {
template <typename ClusterType>
auto fmt_format = fmt_format_trait<ClusterType>::value();
/**
* Helper function to allocate image data given item size and shape
* used when we want to fill a numpy array and return to python
*/
/**
* Helper function to allocate image data given item size and shape
* used when we want to fill a numpy array and return to python
*/
py::array allocate_image_data(size_t item_size,
const std::vector<size_t> &shape) {
py::array image_data;
if (item_size == 1) {
image_data = py::array_t<uint8_t>(shape);
} else if (item_size == 2) {
image_data = py::array_t<uint16_t>(shape);
image_data = py::array_t<uint16_t>(shape);
} else if (item_size == 4) {
image_data = py::array_t<uint32_t>(shape);
}

View File

@@ -58,10 +58,8 @@ class ClusterFinderMTWrapper
size_t m_sink_size() const { return this->m_sink.sizeGuess(); }
};
TEST_CASE("multithreaded cluster finder", "[.with-data]") {
auto fpath =
test_data_path() / "raw/moench03/cu_half_speed_master_4.json";
auto fpath = test_data_path() / "raw/moench03/cu_half_speed_master_4.json";
REQUIRE(std::filesystem::exists(fpath));

View File

@@ -10,7 +10,6 @@ using aare::Cluster;
using aare::ClusterVector;
using C1 = Cluster<int32_t, 2, 2>;
TEST_CASE("A newly created ClusterVector is empty") {
ClusterVector<C1> cv(4);
REQUIRE(cv.empty());
@@ -174,7 +173,8 @@ TEST_CASE("Push back more than initial capacity") {
REQUIRE(initial_data != cv.data());
}
TEST_CASE("Concatenate two cluster vectors where the first has enough capacity") {
TEST_CASE(
"Concatenate two cluster vectors where the first has enough capacity") {
ClusterVector<Cluster<int32_t, 2, 2>> cv1(12);
Cluster<int32_t, 2, 2> c1 = {1, 2, {3, 4, 5, 6}};
cv1.push_back(c1);

View File

@@ -5,9 +5,8 @@
namespace aare {
CtbRawFile::CtbRawFile(const std::filesystem::path &fname) : m_master(fname) {
if( (m_master.detector_type() != DetectorType::ChipTestBoard) &&
(m_master.detector_type() != DetectorType::Xilinx_ChipTestBoard) )
{
if ((m_master.detector_type() != DetectorType::ChipTestBoard) &&
(m_master.detector_type() != DetectorType::Xilinx_ChipTestBoard)) {
throw std::runtime_error(LOCATION + "Not a Ctb file");
}
@@ -15,8 +14,9 @@ CtbRawFile::CtbRawFile(const std::filesystem::path &fname) : m_master(fname) {
// open the first subfile
m_file.open(m_master.data_fname(0, 0), std::ios::binary);
if(!m_file)
throw std::runtime_error(LOCATION + "Could not open: " + m_master.data_fname(0, 0).string());
if (!m_file)
throw std::runtime_error(
LOCATION + "Could not open: " + m_master.data_fname(0, 0).string());
}
void CtbRawFile::read_into(std::byte *image_buf, DetectorHeader *header) {
@@ -63,7 +63,6 @@ void CtbRawFile::find_subfiles() {
// we can semi safely assume that there is only one module for CTB
while (std::filesystem::exists(m_master.data_fname(0, m_num_subfiles)))
m_num_subfiles++;
}
void CtbRawFile::open_data_file(size_t subfile_index) {

View File

@@ -1,6 +1,5 @@
// SPDX-License-Identifier: MPL-2.0
#include "aare/Dtype.hpp"
#include <catch2/catch_test_macros.hpp>

View File

@@ -71,7 +71,8 @@ TEST_CASE("Seek in a JungfrauDataFile", "[.with-data]") {
REQUIRE_THROWS(f.seek(86356)); // out of range
}
TEST_CASE("Open a Jungfrau data file with non zero file index", "[.with-data]") {
TEST_CASE("Open a Jungfrau data file with non zero file index",
"[.with-data]") {
auto fpath = test_data_path() / "dat" / "AldoJF65k_000003.dat";
REQUIRE(std::filesystem::exists(fpath));

View File

@@ -105,43 +105,43 @@ TEST_CASE("Indexing of a 3D image") {
REQUIRE(img(2, 3, 1) == 23);
}
TEST_CASE("Access to data using a pointer"){
TEST_CASE("Access to data using a pointer") {
// This pattern is discouraged but sometimes useful
NDArray<int,2> img{{4,5},0};
int* data_ptr = img.data();
for(int i=0; i < img.size(); ++i){
data_ptr[i] = i*2;
NDArray<int, 2> img{{4, 5}, 0};
int *data_ptr = img.data();
for (int i = 0; i < img.size(); ++i) {
data_ptr[i] = i * 2;
}
// Cross check using operator[]
for(int i=0; i < img.size(); ++i){
REQUIRE(img[i] == i*2);
for (int i = 0; i < img.size(); ++i) {
REQUIRE(img[i] == i * 2);
}
}
TEST_CASE("Access to data using a pointer for a const NDArray"){
TEST_CASE("Access to data using a pointer for a const NDArray") {
// This pattern is discouraged but sometimes useful
// Using a lambda to create a const NDArray with known data
const NDArray<int,2> arr = [](){
NDArray<int,2> img{{4,5},0};
int* data_ptr = img.data();
for(int i=0; i < img.size(); ++i){
data_ptr[i] = i*3;
const NDArray<int, 2> arr = []() {
NDArray<int, 2> img{{4, 5}, 0};
int *data_ptr = img.data();
for (int i = 0; i < img.size(); ++i) {
data_ptr[i] = i * 3;
}
return img;
}();
// Cross check using data() pointer, if compiles we can get a const pointer
const int* const_data_ptr = arr.data();
for(int i=0; i < arr.size(); ++i){
REQUIRE(const_data_ptr[i] == i*3);
const int *const_data_ptr = arr.data();
for (int i = 0; i < arr.size(); ++i) {
REQUIRE(const_data_ptr[i] == i * 3);
}
}
TEST_CASE("Use *buffer"){
// Another useful but discouraged pattern. But can be useful when getting data
// from external sources
TEST_CASE("Use *buffer") {
// Another useful but discouraged pattern. But can be useful when getting
// data from external sources
Shape<2> shape{{4, 5}};
NDArray<int, 2> src(shape);
NDArray<int, 2> dst(shape);
@@ -491,64 +491,60 @@ TEST_CASE("Construct an NDArray from an std::array") {
}
}
TEST_CASE("Copy construct an NDArray"){
NDArray<int,2> a({{3,4}},0);
a(1,1) = 42;
a(2,3) = 84;
TEST_CASE("Copy construct an NDArray") {
NDArray<int, 2> a({{3, 4}}, 0);
a(1, 1) = 42;
a(2, 3) = 84;
NDArray<int,2> b(a);
REQUIRE(b.shape() == Shape<2>{3,4});
NDArray<int, 2> b(a);
REQUIRE(b.shape() == Shape<2>{3, 4});
REQUIRE(b.size() == 12);
REQUIRE(b(1,1) == 42);
REQUIRE(b(2,3) == 84);
REQUIRE(b(1, 1) == 42);
REQUIRE(b(2, 3) == 84);
// Modifying b should not affect a
b(1,1) = 7;
REQUIRE(a(1,1) == 42);
b(1, 1) = 7;
REQUIRE(a(1, 1) == 42);
REQUIRE(a.data() != b.data());
}
TEST_CASE("Move construct an NDArray") {
NDArray<int, 2> a({{3, 4}}, 0);
a(1, 1) = 42;
a(2, 3) = 84;
TEST_CASE("Move construct an NDArray"){
NDArray<int,2> a({{3,4}},0);
a(1,1) = 42;
a(2,3) = 84;
NDArray<int,2> b(std::move(a));
REQUIRE(b.shape() == Shape<2>{3,4});
NDArray<int, 2> b(std::move(a));
REQUIRE(b.shape() == Shape<2>{3, 4});
REQUIRE(b.size() == 12);
REQUIRE(b(1,1) == 42);
REQUIRE(b(2,3) == 84);
REQUIRE(b(1, 1) == 42);
REQUIRE(b(2, 3) == 84);
// The moved from object should be in a unspecified but valid state.
// This means original array pointer should be null, and size zero
REQUIRE(a.size() == 0);
REQUIRE(a.shape() == Shape<2>{0,0});
REQUIRE(a.shape() == Shape<2>{0, 0});
REQUIRE(a.data() == nullptr);
}
TEST_CASE("Move construct from an array with Ndim + 1") {
NDArray<int, 3> a({{1,2,2}}, 0);
NDArray<int, 3> a({{1, 2, 2}}, 0);
a(0, 0, 0) = 1;
a(0, 0, 1) = 2;
a(0, 1, 0) = 3;
a(0, 1, 1) = 4;
NDArray<int, 2> b(std::move(a));
REQUIRE(b.shape() == Shape<2>{2,2});
REQUIRE(b.shape() == Shape<2>{2, 2});
REQUIRE(b.size() == 4);
REQUIRE(b(0, 0) == 1);
REQUIRE(b(0, 1) == 2);
REQUIRE(b(1, 0) == 3);
REQUIRE(b(1, 1) == 4);
}
TEST_CASE("Move construct from an array with Ndim + 1 throws on size mismatch") {
NDArray<int, 3> a({{2,2,2}}, 0);
TEST_CASE(
"Move construct from an array with Ndim + 1 throws on size mismatch") {
NDArray<int, 3> a({{2, 2, 2}}, 0);
REQUIRE_THROWS(NDArray<int, 2>(std::move(a)));
}

View File

@@ -2,10 +2,10 @@
#include "aare/NDView.hpp"
#include <catch2/catch_test_macros.hpp>
#include <cstddef>
#include <iostream>
#include <numeric>
#include <vector>
#include <cstddef>
using aare::NDView;
using aare::Shape;
@@ -23,7 +23,6 @@ TEST_CASE("Element reference 1D") {
}
}
TEST_CASE("Assign elements through () and []") {
std::vector<int> vec;
for (int i = 0; i != 10; ++i) {
@@ -31,11 +30,10 @@ TEST_CASE("Assign elements through () and []") {
}
NDView<int, 1> data(vec.data(), Shape<1>{10});
REQUIRE(vec.size() == static_cast<size_t>(data.size()));
data[3] = 187;
data(4) = 512;
REQUIRE(data(0) == 0);
REQUIRE(data[0] == 0);
REQUIRE(data(1) == 1);
@@ -56,8 +54,6 @@ TEST_CASE("Assign elements through () and []") {
REQUIRE(data[8] == 8);
REQUIRE(data(9) == 9);
REQUIRE(data[9] == 9);
}
TEST_CASE("Element reference 1D with a const NDView") {
@@ -73,7 +69,6 @@ TEST_CASE("Element reference 1D with a const NDView") {
}
}
TEST_CASE("Element reference 2D") {
std::vector<int> vec(12);
std::iota(vec.begin(), vec.end(), 0);
@@ -190,8 +185,6 @@ TEST_CASE("iterators") {
}
}
TEST_CASE("divide with another NDView") {
std::vector<int> vec0{9, 12, 3};
std::vector<int> vec1{3, 2, 1};
@@ -229,7 +222,7 @@ TEST_CASE("compare two views") {
REQUIRE((view1 == view2));
}
TEST_CASE("Compare two views with different size"){
TEST_CASE("Compare two views with different size") {
std::vector<int> vec1(12);
std::iota(vec1.begin(), vec1.end(), 0);
NDView<int, 2> view1(vec1.data(), Shape<2>{3, 4});
@@ -241,7 +234,7 @@ TEST_CASE("Compare two views with different size"){
REQUIRE_FALSE(view1 == view2);
}
TEST_CASE("Compare two views with same size but different shape"){
TEST_CASE("Compare two views with same size but different shape") {
std::vector<int> vec1(12);
std::iota(vec1.begin(), vec1.end(), 0);
NDView<int, 2> view1(vec1.data(), Shape<2>{3, 4});
@@ -262,10 +255,9 @@ TEST_CASE("Create a view over a vector") {
REQUIRE(v[11] == 11);
}
TEST_CASE("NDView over byte"){
TEST_CASE("NDView over byte") {
std::vector<std::byte> buf(5);
auto v = aare::make_view(buf);
REQUIRE(v.shape()[0] == 5);
REQUIRE(v[0] == std::byte{0});
}

View File

@@ -105,8 +105,8 @@ NDArray<ssize_t, 2> GenerateEigerFlipRowsPixelMap() {
}
NDArray<ssize_t, 2> GenerateMH02SingleCounterPixelMap() {
// This is the pixel map for a single counter Matterhorn02, i.e. 48x48 pixels.
// Data is read from two transceivers in blocks of 4 pixels.
// This is the pixel map for a single counter Matterhorn02, i.e. 48x48
// pixels. Data is read from two transceivers in blocks of 4 pixels.
NDArray<ssize_t, 2> order_map({48, 48});
size_t offset = 0;
size_t nSamples = 4;
@@ -131,8 +131,7 @@ NDArray<ssize_t, 3> GenerateMH02FourCounterPixelMap() {
for (int row = 0; row < 48; row++) {
for (int col = 0; col < 48; col++) {
order_map(counter, row, col) =
single_counter_map(row, col) +
counter * 48 * 48;
single_counter_map(row, col) + counter * 48 * 48;
}
}
}

View File

@@ -62,7 +62,6 @@ Frame RawFile::read_roi(const size_t roi_index) {
return get_frame(m_current_frame++, roi_index);
}
std::vector<Frame> RawFile::read_rois() {
if (!m_master.rois()) {
@@ -83,8 +82,6 @@ std::vector<Frame> RawFile::read_rois() {
return frames;
}
Frame RawFile::read_frame() {
if (m_master.rois().has_value() && m_master.rois()->size() > 1) {
throw std::runtime_error(LOCATION +
@@ -473,7 +470,7 @@ std::vector<Frame> RawFile::read_n(size_t n_frames) {
}
std::vector<Frame> RawFile::read_n_with_roi(const size_t n_frames,
const size_t roi_index) {
const size_t roi_index) {
if (roi_index >= num_rois()) {
throw std::runtime_error(LOCATION + "ROI index out of range.");
}

View File

@@ -255,7 +255,7 @@ void RawMasterFile::parse_json(std::istream &is) {
// TODO! Not valid for CTB but not changing api right now!
// Not all detectors write the bitdepth but in case
// its not there it is 16
if(j.contains("Dynamic Range") && j["Dynamic Range"].is_number()){
if (j.contains("Dynamic Range") && j["Dynamic Range"].is_number()) {
m_bitdepth = j["Dynamic Range"];
} else {
m_bitdepth = 16;

View File

@@ -398,7 +398,7 @@ TEST_CASE("Parse EIGER 7.2 master from string stream") {
REQUIRE(f.timing_mode() == TimingMode::Auto);
REQUIRE(f.geometry().col == 2);
REQUIRE(f.geometry().row == 2);
REQUIRE(f.image_size_in_bytes() == 524288);
REQUIRE(f.pixels_x() == 512);
REQUIRE(f.pixels_y() == 256);

View File

@@ -1,6 +1,5 @@
// SPDX-License-Identifier: MPL-2.0
#include <aare/algorithm.hpp>
#include <catch2/catch_test_macros.hpp>

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MPL-2.0
#include "aare/decode.hpp"
#include <fmt/format.h>
#include <cmath>
#include <fmt/format.h>
namespace aare {
uint16_t adc_sar_05_06_07_08decode64to16(uint64_t input) {
@@ -24,7 +24,7 @@ uint16_t adc_sar_05_06_07_08decode64to16(uint64_t input) {
}
void adc_sar_05_06_07_08decode64to16(NDView<uint64_t, 2> input,
NDView<uint16_t, 2> output) {
NDView<uint16_t, 2> output) {
if (input.shape() != output.shape()) {
throw std::invalid_argument(LOCATION +
" input and output shapes must match");
@@ -139,49 +139,50 @@ void apply_custom_weights(NDView<uint16_t, 1> input, NDView<double, 1> output,
}
}
uint32_t mask32to24bits(uint32_t input, BitOffset offset){
uint32_t mask32to24bits(uint32_t input, BitOffset offset) {
constexpr uint32_t mask24bits{0xFFFFFF};
return (input >> offset.value()) & mask24bits;
}
void expand24to32bit(NDView<uint8_t,1> input, NDView<uint32_t,1> output, BitOffset bit_offset){
void expand24to32bit(NDView<uint8_t, 1> input, NDView<uint32_t, 1> output,
BitOffset bit_offset) {
ssize_t bytes_per_channel = 3; //24bit
ssize_t min_input_size = output.size()*bytes_per_channel;
ssize_t bytes_per_channel = 3; // 24bit
ssize_t min_input_size = output.size() * bytes_per_channel;
//if we have an offset we need one more byte in the input data
// if we have an offset we need one more byte in the input data
if (bit_offset.value())
min_input_size += 1;
min_input_size += 1;
if (input.size() < min_input_size)
throw std::runtime_error(fmt::format(
"{} Mismatch between input and output size. Output "
"size of {} with bit offset {} requires an input of at least {} "
"bytes. Called with input size: {} output size: {}",
LOCATION, output.size(), bit_offset.value(), min_input_size, input.size(), output.size()));
LOCATION, output.size(), bit_offset.value(), min_input_size,
input.size(), output.size()));
auto* in = input.data();
auto *in = input.data();
if(bit_offset.value()){
//If there is a bit_offset we copy 4 bytes and then
//mask out the correct ones.
for (auto& v : output){
if (bit_offset.value()) {
// If there is a bit_offset we copy 4 bytes and then
// mask out the correct ones.
for (auto &v : output) {
uint32_t val{};
std::memcpy(&val, in, sizeof(val));
v = mask32to24bits(val, bit_offset);
in += bytes_per_channel;
}
}else{
//If there is no offset we can directly copy the bits
//without masking
for (auto& v : output){
}
} else {
// If there is no offset we can directly copy the bits
// without masking
for (auto &v : output) {
uint32_t val{};
std::memcpy(&val, in, 3);
v = val;
in += bytes_per_channel;
}
}
}
}
} // namespace aare

View File

@@ -75,35 +75,32 @@ TEST_CASE("test_apply_custom_weights") {
CHECK_THAT(output, WithinAbs(6.34, 0.001));
}
TEST_CASE("Mask 32 bit unsigned integer to 24 bit"){
//any number less than 2**24 (16777216) should be the same
CHECK(aare::mask32to24bits(0)==0);
CHECK(aare::mask32to24bits(19)==19);
CHECK(aare::mask32to24bits(29875)==29875);
CHECK(aare::mask32to24bits(1092177)==1092177);
CHECK(aare::mask32to24bits(0xFFFF)==0xFFFF);
CHECK(aare::mask32to24bits(0xFFFFFFFF)==0xFFFFFF);
TEST_CASE("Mask 32 bit unsigned integer to 24 bit") {
// any number less than 2**24 (16777216) should be the same
CHECK(aare::mask32to24bits(0) == 0);
CHECK(aare::mask32to24bits(19) == 19);
CHECK(aare::mask32to24bits(29875) == 29875);
CHECK(aare::mask32to24bits(1092177) == 1092177);
CHECK(aare::mask32to24bits(0xFFFF) == 0xFFFF);
CHECK(aare::mask32to24bits(0xFFFFFFFF) == 0xFFFFFF);
// Offset specifies that the should ignore 0-7 bits
// at the start
CHECK(aare::mask32to24bits(0xFFFF, BitOffset(4))==0xFFF);
CHECK(aare::mask32to24bits(0xFF0000d9)==0xd9);
CHECK(aare::mask32to24bits(0xFF000d9F, BitOffset(4))==0xF000d9);
CHECK(aare::mask32to24bits(16777217)==1);
CHECK(aare::mask32to24bits(15,BitOffset(7))==0);
//Highest bit set to 1 should just be excluded
//lowest 4 bits set to 1
CHECK(aare::mask32to24bits(0x8000000f,BitOffset(7))==0);
CHECK(aare::mask32to24bits(0xFFFF, BitOffset(4)) == 0xFFF);
CHECK(aare::mask32to24bits(0xFF0000d9) == 0xd9);
CHECK(aare::mask32to24bits(0xFF000d9F, BitOffset(4)) == 0xF000d9);
CHECK(aare::mask32to24bits(16777217) == 1);
CHECK(aare::mask32to24bits(15, BitOffset(7)) == 0);
// Highest bit set to 1 should just be excluded
// lowest 4 bits set to 1
CHECK(aare::mask32to24bits(0x8000000f, BitOffset(7)) == 0);
}
TEST_CASE("Expand container with 24 bit data to 32"){
TEST_CASE("Expand container with 24 bit data to 32") {
{
uint8_t buffer[] = {
0x00, 0x00, 0x00,
0x00, 0x00, 0x00,
0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
aare::NDView<uint8_t, 1> input(&buffer[0], {9});
@@ -116,9 +113,7 @@ TEST_CASE("Expand container with 24 bit data to 32"){
}
{
uint8_t buffer[] = {
0x0F, 0x00, 0x00,
0xFF, 0x00, 0x00,
0xFF, 0xFF, 0xFF,
0x0F, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
};
aare::NDView<uint8_t, 1> input(&buffer[0], {9});
@@ -131,9 +126,7 @@ TEST_CASE("Expand container with 24 bit data to 32"){
}
{
uint8_t buffer[] = {
0x00, 0x00, 0xFF,
0xFF, 0xFF, 0x00,
0x00, 0xFF, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00,
};
aare::NDView<uint8_t, 1> input(&buffer[0], {9});
@@ -147,20 +140,16 @@ TEST_CASE("Expand container with 24 bit data to 32"){
REQUIRE_THROWS(aare::expand24to32bit(input, out.view(), BitOffset(4)));
}
{
//For use with offset we need an extra byte
uint8_t buffer[] = {
0x00, 0x00, 0xFF,
0xFF, 0xFF, 0x00,
0x00, 0xFF, 0x00, 0x00
};
// For use with offset we need an extra byte
uint8_t buffer[] = {0x00, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0x00, 0x00};
aare::NDView<uint8_t, 1> input(&buffer[0], {10});
aare::NDArray<uint32_t, 1> out({3}); //still output.size == 3
aare::NDArray<uint32_t, 1> out({3}); // still output.size == 3
aare::expand24to32bit(input, out.view(), BitOffset(4));
CHECK(out(0) == 0xFFF000);
CHECK(out(1) == 0xFFF);
CHECK(out(2) == 0xFF0);
}
}

View File

@@ -51,23 +51,20 @@ void assert_failed(const std::string &msg) {
// throw std::runtime_error("Could not decode detector to string");
// }
BitOffset::BitOffset(uint32_t offset){
if (offset>7)
throw std::runtime_error(fmt::format("{} BitOffset needs to be <8: Called with {}", LOCATION, offset));
BitOffset::BitOffset(uint32_t offset) {
if (offset > 7)
throw std::runtime_error(fmt::format(
"{} BitOffset needs to be <8: Called with {}", LOCATION, offset));
m_offset = static_cast<uint8_t>(offset);
}
bool BitOffset::operator==(const BitOffset& other) const {
return m_offset == other.m_offset;
}
bool BitOffset::operator<(const BitOffset& other) const {
return m_offset < other.m_offset;
}
bool BitOffset::operator==(const BitOffset &other) const {
return m_offset == other.m_offset;
}
bool BitOffset::operator<(const BitOffset &other) const {
return m_offset < other.m_offset;
}
} // namespace aare

View File

@@ -4,8 +4,6 @@
#include <catch2/catch_test_macros.hpp>
#include <string>
TEST_CASE("Enum values") {
// Since some of the enums are written to file we need to make sure
// they match the value in the slsDetectorPackage
@@ -38,23 +36,22 @@ TEST_CASE("DynamicCluster creation") {
REQUIRE(c2.data() != nullptr);
}
TEST_CASE("Basic ops on BitOffset"){
TEST_CASE("Basic ops on BitOffset") {
REQUIRE_THROWS(aare::BitOffset(10));
aare::BitOffset offset(5);
REQUIRE(offset.value()==5);
REQUIRE(offset.value() == 5);
aare::BitOffset offset2;
REQUIRE(offset2.value()==0);
REQUIRE(offset2.value() == 0);
aare::BitOffset offset3(offset);
REQUIRE(offset3.value()==5);
REQUIRE(offset3.value() == 5);
REQUIRE(offset==offset3);
REQUIRE(offset == offset3);
//Now assign offset to offset2 which should get the value 5
// Now assign offset to offset2 which should get the value 5
offset2 = offset;
REQUIRE(offset2.value()==5);
REQUIRE(offset2==offset);
REQUIRE(offset2.value() == 5);
REQUIRE(offset2 == offset);
}

View File

@@ -53,7 +53,6 @@ template <> FrameDiscardPolicy string_to(const std::string &arg) {
arg + "\"");
}
template <> DACIndex string_to(const std::string &arg) {
if (arg == "dac 0")
return DACIndex::DAC_0;
@@ -236,12 +235,12 @@ template <> DACIndex string_to(const std::string &arg) {
"\"");
}
std::string remove_unit(std::string &str) {
auto it = str.begin();
while (it != str.end()) {
if (std::isalpha(*it)) {
// Check if this is scientific notation (e or E followed by optional sign and digits)
// Check if this is scientific notation (e or E followed by optional
// sign and digits)
if (((*it == 'e' || *it == 'E') && (it + 1) != str.end())) {
auto next = it + 1;
// Skip optional sign

View File

@@ -12,7 +12,6 @@
namespace aare {
std::string remove_unit(std::string &str);
template <typename T>
@@ -40,7 +39,6 @@ T string_to(const std::string &t, const std::string &unit) {
}
}
// if T has a constructor that takes a string, lets use it.
// template <class T> T string_to(const std::string &arg) { return T{arg}; }
template <typename T> T string_to(const std::string &arg) {
@@ -81,10 +79,4 @@ template <> FrameDiscardPolicy string_to(const std::string &arg);
*/
template <> DACIndex string_to(const std::string &arg);
} // namespace aare

View File

@@ -10,7 +10,8 @@ using aare::string_to;
TEST_CASE("DetectorType string to enum") {
REQUIRE(string_to<aare::DetectorType>("Generic") ==
aare::DetectorType::Generic);
REQUIRE(string_to<aare::DetectorType>("Eiger") == aare::DetectorType::Eiger);
REQUIRE(string_to<aare::DetectorType>("Eiger") ==
aare::DetectorType::Eiger);
REQUIRE(string_to<aare::DetectorType>("Gotthard") ==
aare::DetectorType::Gotthard);
REQUIRE(string_to<aare::DetectorType>("Jungfrau") ==
@@ -36,7 +37,8 @@ TEST_CASE("DetectorType string to enum") {
TEST_CASE("TimingMode string to enum") {
REQUIRE(string_to<aare::TimingMode>("auto") == aare::TimingMode::Auto);
REQUIRE(string_to<aare::TimingMode>("trigger") == aare::TimingMode::Trigger);
REQUIRE(string_to<aare::TimingMode>("trigger") ==
aare::TimingMode::Trigger);
REQUIRE_THROWS(string_to<aare::TimingMode>("invalid_mode"));
}
@@ -88,34 +90,50 @@ TEST_CASE("DACIndex string to enum") {
REQUIRE(string_to<aare::DACIndex>("vcp") == aare::DACIndex::VCP);
REQUIRE(string_to<aare::DACIndex>("vcn") == aare::DACIndex::VCN);
REQUIRE(string_to<aare::DACIndex>("vishaper") == aare::DACIndex::VISHAPER);
REQUIRE(string_to<aare::DACIndex>("vthreshold") == aare::DACIndex::VTHRESHOLD);
REQUIRE(string_to<aare::DACIndex>("vthreshold") ==
aare::DACIndex::VTHRESHOLD);
REQUIRE(string_to<aare::DACIndex>("vref_ds") == aare::DACIndex::VREF_DS);
REQUIRE(string_to<aare::DACIndex>("vout_cm") == aare::DACIndex::VOUT_CM);
REQUIRE(string_to<aare::DACIndex>("vin_cm") == aare::DACIndex::VIN_CM);
REQUIRE(string_to<aare::DACIndex>("vref_comp") == aare::DACIndex::VREF_COMP);
REQUIRE(string_to<aare::DACIndex>("vref_comp") ==
aare::DACIndex::VREF_COMP);
REQUIRE(string_to<aare::DACIndex>("vb_comp") == aare::DACIndex::VB_COMP);
REQUIRE(string_to<aare::DACIndex>("vdd_prot") == aare::DACIndex::VDD_PROT);
REQUIRE(string_to<aare::DACIndex>("vin_com") == aare::DACIndex::VIN_COM);
REQUIRE(string_to<aare::DACIndex>("vref_prech") == aare::DACIndex::VREF_PRECH);
REQUIRE(string_to<aare::DACIndex>("vb_pixbuf") == aare::DACIndex::VB_PIXBUF);
REQUIRE(string_to<aare::DACIndex>("vref_prech") ==
aare::DACIndex::VREF_PRECH);
REQUIRE(string_to<aare::DACIndex>("vb_pixbuf") ==
aare::DACIndex::VB_PIXBUF);
REQUIRE(string_to<aare::DACIndex>("vb_ds") == aare::DACIndex::VB_DS);
REQUIRE(string_to<aare::DACIndex>("vref_h_adc") == aare::DACIndex::VREF_H_ADC);
REQUIRE(string_to<aare::DACIndex>("vb_comp_fe") == aare::DACIndex::VB_COMP_FE);
REQUIRE(string_to<aare::DACIndex>("vb_comp_adc") == aare::DACIndex::VB_COMP_ADC);
REQUIRE(string_to<aare::DACIndex>("vref_h_adc") ==
aare::DACIndex::VREF_H_ADC);
REQUIRE(string_to<aare::DACIndex>("vb_comp_fe") ==
aare::DACIndex::VB_COMP_FE);
REQUIRE(string_to<aare::DACIndex>("vb_comp_adc") ==
aare::DACIndex::VB_COMP_ADC);
REQUIRE(string_to<aare::DACIndex>("vcom_cds") == aare::DACIndex::VCOM_CDS);
REQUIRE(string_to<aare::DACIndex>("vref_rstore") == aare::DACIndex::VREF_RSTORE);
REQUIRE(string_to<aare::DACIndex>("vb_opa_1st") == aare::DACIndex::VB_OPA_1ST);
REQUIRE(string_to<aare::DACIndex>("vref_comp_fe") == aare::DACIndex::VREF_COMP_FE);
REQUIRE(string_to<aare::DACIndex>("vcom_adc1") == aare::DACIndex::VCOM_ADC1);
REQUIRE(string_to<aare::DACIndex>("vref_l_adc") == aare::DACIndex::VREF_L_ADC);
REQUIRE(string_to<aare::DACIndex>("vref_rstore") ==
aare::DACIndex::VREF_RSTORE);
REQUIRE(string_to<aare::DACIndex>("vb_opa_1st") ==
aare::DACIndex::VB_OPA_1ST);
REQUIRE(string_to<aare::DACIndex>("vref_comp_fe") ==
aare::DACIndex::VREF_COMP_FE);
REQUIRE(string_to<aare::DACIndex>("vcom_adc1") ==
aare::DACIndex::VCOM_ADC1);
REQUIRE(string_to<aare::DACIndex>("vref_l_adc") ==
aare::DACIndex::VREF_L_ADC);
REQUIRE(string_to<aare::DACIndex>("vref_cds") == aare::DACIndex::VREF_CDS);
REQUIRE(string_to<aare::DACIndex>("vb_cs") == aare::DACIndex::VB_CS);
REQUIRE(string_to<aare::DACIndex>("vb_opa_fd") == aare::DACIndex::VB_OPA_FD);
REQUIRE(string_to<aare::DACIndex>("vcom_adc2") == aare::DACIndex::VCOM_ADC2);
REQUIRE(string_to<aare::DACIndex>("vb_opa_fd") ==
aare::DACIndex::VB_OPA_FD);
REQUIRE(string_to<aare::DACIndex>("vcom_adc2") ==
aare::DACIndex::VCOM_ADC2);
REQUIRE(string_to<aare::DACIndex>("vcassh") == aare::DACIndex::VCASSH);
REQUIRE(string_to<aare::DACIndex>("vth2") == aare::DACIndex::VTH2);
REQUIRE(string_to<aare::DACIndex>("vrshaper_n") == aare::DACIndex::VRSHAPER_N);
REQUIRE(string_to<aare::DACIndex>("vipre_out") == aare::DACIndex::VIPRE_OUT);
REQUIRE(string_to<aare::DACIndex>("vrshaper_n") ==
aare::DACIndex::VRSHAPER_N);
REQUIRE(string_to<aare::DACIndex>("vipre_out") ==
aare::DACIndex::VIPRE_OUT);
REQUIRE(string_to<aare::DACIndex>("vth3") == aare::DACIndex::VTH3);
REQUIRE(string_to<aare::DACIndex>("vth1") == aare::DACIndex::VTH1);
REQUIRE(string_to<aare::DACIndex>("vicin") == aare::DACIndex::VICIN);
@@ -124,31 +142,47 @@ TEST_CASE("DACIndex string to enum") {
REQUIRE(string_to<aare::DACIndex>("vipre") == aare::DACIndex::VIPRE);
REQUIRE(string_to<aare::DACIndex>("vcal_p") == aare::DACIndex::VCAL_P);
REQUIRE(string_to<aare::DACIndex>("vdcsh") == aare::DACIndex::VDCSH);
REQUIRE(string_to<aare::DACIndex>("vbp_colbuf") == aare::DACIndex::VBP_COLBUF);
REQUIRE(string_to<aare::DACIndex>("vbp_colbuf") ==
aare::DACIndex::VBP_COLBUF);
REQUIRE(string_to<aare::DACIndex>("vb_sda") == aare::DACIndex::VB_SDA);
REQUIRE(string_to<aare::DACIndex>("vcasc_sfp") == aare::DACIndex::VCASC_SFP);
REQUIRE(string_to<aare::DACIndex>("vipre_cds") == aare::DACIndex::VIPRE_CDS);
REQUIRE(string_to<aare::DACIndex>("ibias_sfp") == aare::DACIndex::IBIAS_SFP);
REQUIRE(string_to<aare::DACIndex>("trimbits") == aare::DACIndex::TRIMBIT_SCAN);
REQUIRE(string_to<aare::DACIndex>("highvoltage") == aare::DACIndex::HIGH_VOLTAGE);
REQUIRE(string_to<aare::DACIndex>("vcasc_sfp") ==
aare::DACIndex::VCASC_SFP);
REQUIRE(string_to<aare::DACIndex>("vipre_cds") ==
aare::DACIndex::VIPRE_CDS);
REQUIRE(string_to<aare::DACIndex>("ibias_sfp") ==
aare::DACIndex::IBIAS_SFP);
REQUIRE(string_to<aare::DACIndex>("trimbits") ==
aare::DACIndex::TRIMBIT_SCAN);
REQUIRE(string_to<aare::DACIndex>("highvoltage") ==
aare::DACIndex::HIGH_VOLTAGE);
REQUIRE(string_to<aare::DACIndex>("iodelay") == aare::DACIndex::IO_DELAY);
REQUIRE(string_to<aare::DACIndex>("temp_adc") == aare::DACIndex::TEMPERATURE_ADC);
REQUIRE(string_to<aare::DACIndex>("temp_fpga") == aare::DACIndex::TEMPERATURE_FPGA);
REQUIRE(string_to<aare::DACIndex>("temp_fpgaext") == aare::DACIndex::TEMPERATURE_FPGAEXT);
REQUIRE(string_to<aare::DACIndex>("temp_10ge") == aare::DACIndex::TEMPERATURE_10GE);
REQUIRE(string_to<aare::DACIndex>("temp_dcdc") == aare::DACIndex::TEMPERATURE_DCDC);
REQUIRE(string_to<aare::DACIndex>("temp_sodl") == aare::DACIndex::TEMPERATURE_SODL);
REQUIRE(string_to<aare::DACIndex>("temp_sodr") == aare::DACIndex::TEMPERATURE_SODR);
REQUIRE(string_to<aare::DACIndex>("temp_fpgafl") == aare::DACIndex::TEMPERATURE_FPGA2);
REQUIRE(string_to<aare::DACIndex>("temp_fpgafr") == aare::DACIndex::TEMPERATURE_FPGA3);
REQUIRE(string_to<aare::DACIndex>("temp_slowadc") == aare::DACIndex::SLOW_ADC_TEMP);
REQUIRE(string_to<aare::DACIndex>("temp_adc") ==
aare::DACIndex::TEMPERATURE_ADC);
REQUIRE(string_to<aare::DACIndex>("temp_fpga") ==
aare::DACIndex::TEMPERATURE_FPGA);
REQUIRE(string_to<aare::DACIndex>("temp_fpgaext") ==
aare::DACIndex::TEMPERATURE_FPGAEXT);
REQUIRE(string_to<aare::DACIndex>("temp_10ge") ==
aare::DACIndex::TEMPERATURE_10GE);
REQUIRE(string_to<aare::DACIndex>("temp_dcdc") ==
aare::DACIndex::TEMPERATURE_DCDC);
REQUIRE(string_to<aare::DACIndex>("temp_sodl") ==
aare::DACIndex::TEMPERATURE_SODL);
REQUIRE(string_to<aare::DACIndex>("temp_sodr") ==
aare::DACIndex::TEMPERATURE_SODR);
REQUIRE(string_to<aare::DACIndex>("temp_fpgafl") ==
aare::DACIndex::TEMPERATURE_FPGA2);
REQUIRE(string_to<aare::DACIndex>("temp_fpgafr") ==
aare::DACIndex::TEMPERATURE_FPGA3);
REQUIRE(string_to<aare::DACIndex>("temp_slowadc") ==
aare::DACIndex::SLOW_ADC_TEMP);
REQUIRE_THROWS(string_to<aare::DACIndex>("invalid_dac"));
}
TEST_CASE("Remove unit from string") {
using aare::remove_unit;
// Test basic numeric value with unit
{
std::string input = "123.45 V";
@@ -156,7 +190,7 @@ TEST_CASE("Remove unit from string") {
REQUIRE(unit == "V");
REQUIRE(input == "123.45");
}
// Test integer value with unit
{
std::string input = "42 Hz";
@@ -164,7 +198,7 @@ TEST_CASE("Remove unit from string") {
REQUIRE(unit == "Hz");
REQUIRE(input == "42");
}
// Test negative value with unit
{
std::string input = "-50.5 mV";
@@ -172,7 +206,7 @@ TEST_CASE("Remove unit from string") {
REQUIRE(unit == "mV");
REQUIRE(input == "-50.5");
}
// Test value with no unit (only numbers)
{
std::string input = "123.45";
@@ -180,7 +214,7 @@ TEST_CASE("Remove unit from string") {
REQUIRE(unit == "");
REQUIRE(input == "123.45");
}
// Test value with only unit (letters at start)
{
std::string input = "kHz";
@@ -188,7 +222,7 @@ TEST_CASE("Remove unit from string") {
REQUIRE(unit == "kHz");
REQUIRE(input == "");
}
// Test with multiple word units
{
std::string input = "100 degrees Celsius";
@@ -196,7 +230,7 @@ TEST_CASE("Remove unit from string") {
REQUIRE(unit == "degrees Celsius");
REQUIRE(input == "100");
}
// Test with scientific notation
{
std::string input = "1.23e-5 A";
@@ -212,7 +246,7 @@ TEST_CASE("Remove unit from string") {
REQUIRE(unit == "m/s");
REQUIRE(input == "-4.56E6");
}
// Test with scientific notation uppercase
{
std::string input = "5.67E+3 Hz";
@@ -220,7 +254,7 @@ TEST_CASE("Remove unit from string") {
REQUIRE(unit == "Hz");
REQUIRE(input == "5.67E+3");
}
// Test with leading zeros
{
std::string input = "00123 ohm";
@@ -236,7 +270,7 @@ TEST_CASE("Remove unit from string") {
REQUIRE(unit == "ohm");
REQUIRE(input == "00123");
}
// Test empty string
{
std::string input = "";
@@ -260,7 +294,8 @@ TEST_CASE("Conversions from time string to chrono durations") {
REQUIRE(string_to<microseconds>("2.5 ms") == microseconds(2500));
REQUIRE(string_to<milliseconds>("3.5 s") == milliseconds(3500));
REQUIRE(string_to<seconds>("2") == seconds(2)); // No unit defaults to seconds
REQUIRE(string_to<seconds>("2") ==
seconds(2)); // No unit defaults to seconds
REQUIRE_THROWS(string_to<seconds>("10 min")); // Unsupported unit
}