3 Commits

Author SHA1 Message Date
8354439605 droping version spec on sphinx (#202)
All checks were successful
Build on RHEL8 / build (push) Successful in 2m56s
Build on RHEL9 / build (push) Successful in 2m58s
- Removing the version requirement on sphinx since the latest version
works again
- added numpy and matplotlib do the etc/dev-env.yml since they are
needed to import aare
2025-06-13 15:25:43 +02:00
11fa95b23c Improved documentation for ClusterFile on the python side (#201)
- Fixed CI job not doing python docs
- added more docs on cluster file 
- fixed generating docs on cluster vector
2025-06-13 10:41:39 +02:00
4976ec1651 added back chunk_size in python (#199)
All checks were successful
Build on RHEL9 / build (push) Successful in 2m52s
Build on RHEL8 / build (push) Successful in 2m57s
When refactoring the dispatch of the python binding for ClusterFile I
forgot chunk_size. Adding it back in.
Excluded from release notes since the bug was introduced after the last
release and now fixed before the next release.

1. added back chunk_size
2. removed a few commented out lines

closes #197
2025-06-12 09:32:42 +02:00
43 changed files with 285 additions and 2653 deletions

View File

@ -43,7 +43,7 @@ jobs:
run: |
mkdir build
cd build
cmake .. -DAARE_SYSTEM_LIBRARIES=ON -DAARE_DOCS=ON
cmake .. -DAARE_SYSTEM_LIBRARIES=ON -DAARE_PYTHON_BINDINGS=ON -DAARE_DOCS=ON
make -j 2
make docs

View File

@ -53,7 +53,6 @@ option(AARE_DOCS "Build documentation" OFF)
option(AARE_VERBOSE "Verbose output" OFF)
option(AARE_CUSTOM_ASSERT "Use custom assert" OFF)
option(AARE_INSTALL_PYTHONEXT "Install the python extension in the install tree under CMAKE_INSTALL_PREFIX/aare/" OFF)
option(AARE_HDF5 "Hdf5 File Format" OFF)
option(AARE_ASAN "Enable AddressSanitizer" OFF)
# Configure which of the dependencies to use FetchContent for
@ -82,7 +81,7 @@ if(AARE_VERBOSE)
add_compile_definitions(AARE_VERBOSE)
add_compile_definitions(AARE_LOG_LEVEL=aare::logDEBUG5)
else()
add_compile_definitions(AARE_LOG_LEVEL=aare::logINFOBLUE)
add_compile_definitions(AARE_LOG_LEVEL=aare::logERROR)
endif()
if(AARE_CUSTOM_ASSERT)
@ -357,10 +356,6 @@ set(PUBLICHEADERS
include/aare/CtbRawFile.hpp
include/aare/ClusterVector.hpp
include/aare/decode.hpp
include/aare/type_traits.hpp
include/aare/scan_parameters.hpp
include/aare/to_string.hpp
include/aare/string_utils.hpp
include/aare/defs.hpp
include/aare/Dtype.hpp
include/aare/File.hpp
@ -371,7 +366,6 @@ set(PUBLICHEADERS
include/aare/GainMap.hpp
include/aare/geo_helpers.hpp
include/aare/JungfrauDataFile.hpp
include/aare/logger.hpp
include/aare/NDArray.hpp
include/aare/NDView.hpp
include/aare/NumpyFile.hpp
@ -389,8 +383,6 @@ set(PUBLICHEADERS
set(SourceFiles
${CMAKE_CURRENT_SOURCE_DIR}/src/CtbRawFile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/defs.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/to_string.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/string_utils.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Dtype.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/decode.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Frame.cpp
@ -410,22 +402,6 @@ set(SourceFiles
${CMAKE_CURRENT_SOURCE_DIR}/src/utils/ifstream_helpers.cpp
)
# HDF5
if (AARE_HDF5)
find_package(HDF5 1.10 COMPONENTS CXX REQUIRED)
add_definitions(
${HDF5_DEFINITIONS}
)
list (APPEND PUBLICHEADERS
include/aare/Hdf5File.hpp
include/aare/Hdf5MasterFile.hpp
)
list (APPEND SourceFiles
${CMAKE_CURRENT_SOURCE_DIR}/src/Hdf5File.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Hdf5MasterFile.cpp
)
endif (AARE_HDF5)
add_library(aare_core STATIC ${SourceFiles})
target_include_directories(aare_core PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
@ -448,16 +424,6 @@ target_link_libraries(
)
if (AARE_HDF5 AND HDF5_FOUND)
add_definitions(-DHDF5_FOUND)
target_link_libraries(aare_core PUBLIC
${HDF5_LIBRARIES}
)
target_include_directories(aare_core PUBLIC
${HDF5_INCLUDE_DIRS}
)
endif()
set_target_properties(aare_core PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}
PUBLIC_HEADER "${PUBLICHEADERS}"
@ -471,8 +437,6 @@ if(AARE_TESTS)
set(TestSources
${CMAKE_CURRENT_SOURCE_DIR}/src/algorithm.test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/defs.test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/to_string.test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/scan_parameters.test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/decode.test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Dtype.test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Frame.test.cpp
@ -495,18 +459,11 @@ if(AARE_TESTS)
${CMAKE_CURRENT_SOURCE_DIR}/src/utils/task.test.cpp
)
if(HDF5_FOUND)
list (APPEND TestSources
${CMAKE_CURRENT_SOURCE_DIR}/src/Hdf5MasterFile.test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Hdf5File.test.cpp
)
endif()
target_sources(tests PRIVATE ${TestSources} )
endif()
###------------------------------------------------------------------------------------------
###------------------------------------------------------------------------------------------

View File

@ -14,6 +14,7 @@ set(SPHINX_BUILD ${CMAKE_CURRENT_BINARY_DIR})
file(GLOB SPHINX_SOURCE_FILES CONFIGURE_DEPENDS "src/*.rst")
foreach(filename ${SPHINX_SOURCE_FILES})
get_filename_component(fname ${filename} NAME)
message(STATUS "Copying ${filename} to ${SPHINX_BUILD}/src/${fname}")

View File

@ -4,4 +4,5 @@ ClusterFile
.. doxygenclass:: aare::ClusterFile
:members:
:undoc-members:
:private-members:
:private-members:

View File

@ -1,8 +0,0 @@
Hdf5File
===============
.. doxygenclass:: aare::Hdf5File
:members:
:undoc-members:
:private-members:

View File

@ -1,14 +0,0 @@
Hdf5MasterFile
===============
.. doxygenclass:: aare::Hdf5MasterFile
:members:
:undoc-members:
:private-members:
.. doxygenclass:: aare::Hdf5FileNameComponents
:members:
:undoc-members:
:private-members:

View File

@ -31,8 +31,6 @@ AARE
pyJungfrauDataFile
pyRawFile
pyRawMasterFile
pyHdf5File
pyHdf5MasterFile
pyVarClusterFinder
pyFit
@ -57,8 +55,6 @@ AARE
RawFile
RawSubFile
RawMasterFile
Hdf5File
Hdf5MasterFile
VarClusterFinder

View File

@ -2,9 +2,24 @@
ClusterFile
============
The :class:`ClusterFile` class is the main interface to read and write clusters in aare. Unfortunately the
old file format does not include metadata like the cluster size and the data type. This means that the
user has to know this information from other sources. Specifying the wrong cluster size or data type
will lead to garbage data being read.
.. py:currentmodule:: aare
.. autoclass:: ClusterFile
:members:
:undoc-members:
:inherited-members:
Below is the API of the ClusterFile_Cluster3x3i but all variants share the same API.
.. autoclass:: aare._aare.ClusterFile_Cluster3x3i
:special-members: __init__
:members:
:undoc-members:
:show-inheritance:

View File

@ -2,8 +2,10 @@ ClusterVector
================
The ClusterVector, holds clusters from the ClusterFinder. Since it is templated
in C++ we use a suffix indicating the data type in python. The suffix is
``_i`` for integer, ``_f`` for float, and ``_d`` for double.
in C++ we use a suffix indicating the type of cluster it holds. The suffix follows
the same pattern as for ClusterFile i.e. ``ClusterVector_Cluster3x3i``
for a vector holding 3x3 integer clusters.
At the moment the functionality from python is limited and it is not supported
to push_back clusters to the vector. The intended use case is to pass it to
@ -26,7 +28,8 @@ C++ functions that support the ClusterVector or to view it as a numpy array.
.. py:currentmodule:: aare
.. autoclass:: ClusterVector_i
.. autoclass:: aare._aare.ClusterVector_Cluster3x3i
:special-members: __init__
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,10 +0,0 @@
Hdf5File
===================
.. py:currentmodule:: aare
.. autoclass:: Hdf5File
:members:
:undoc-members:
:show-inheritance:
:inherited-members:

View File

@ -1,10 +0,0 @@
Hdf5MasterFile
===================
.. py:currentmodule:: aare
.. autoclass:: Hdf5MasterFile
:members:
:undoc-members:
:show-inheritance:
:inherited-members:

View File

@ -5,9 +5,12 @@ dependencies:
- anaconda-client
- conda-build
- doxygen
- sphinx=7.1.2
- sphinx
- breathe
- sphinx_rtd_theme
- furo
- zeromq
- pybind11
- numpy
- matplotlib

View File

@ -7,7 +7,7 @@ namespace aare {
/**
* @brief RAII File class for reading, and in the future potentially writing
* image files in various formats. Minimal generic interface. For specail
* fuctions plase use the RawFile, NumpyFile or Hdf5File classes directly. Wraps
* fuctions plase use the RawFile or NumpyFile classes directly. Wraps
* FileInterface to abstract the underlying file format
* @note **frame_number** refers the the frame number sent by the detector while
* **frame_index** is the position of the frame in the file

View File

@ -1,7 +1,7 @@
#pragma once
#include "aare/Dtype.hpp"
#include "aare/Frame.hpp"
#include "aare/to_string.hpp"
#include "aare/defs.hpp"
#include <filesystem>
#include <vector>
@ -46,7 +46,7 @@ struct FileConfig {
/**
* @brief FileInterface class to define the interface for file operations
* @note parent class for NumpyFile, RawFile and Hdf5File
* @note parent class for NumpyFile and RawFile
* @note all functions are pure virtual and must be implemented by the derived
* classes
*/

View File

@ -1,211 +0,0 @@
#pragma once
#include "aare/FileInterface.hpp"
#include "aare/Frame.hpp"
#include "aare/Hdf5MasterFile.hpp"
#include "aare/NDArray.hpp" //for pixel map
#include <optional>
namespace aare {
class H5Handles {
std::string file_name;
std::string dataset_name;
H5::H5File file;
H5::DataSet dataset;
H5::DataSpace dataspace;
H5::DataType datatype;
std::unique_ptr<H5::DataSpace> memspace;
std::vector<hsize_t> dims;
std::vector<hsize_t> count;
std::vector<hsize_t> offset;
public:
H5Handles(const std::string &fname, const std::string &dname)
: file_name(fname), dataset_name(dname), file(fname, H5F_ACC_RDONLY),
dataset(file.openDataSet(dname)), dataspace(dataset.getSpace()),
datatype(dataset.getDataType()) {
intialize_dimensions();
initialize_memspace();
}
std::vector<hsize_t> get_dims() const { return dims; }
void seek(size_t frame_index) {
if (frame_index >= dims[0]) {
throw std::runtime_error(LOCATION + "Invalid frame number");
}
offset[0] = static_cast<hsize_t>(frame_index);
}
void get_data_into(size_t frame_index, std::byte *frame_buffer,
size_t n_frames = 1) {
seek(frame_index);
count[0] = static_cast<hsize_t>(n_frames);
// std::cout << "offset:" << ToString(offset) << " count:" <<
// ToString(count) << std::endl;
dataspace.selectHyperslab(H5S_SELECT_SET, count.data(), offset.data());
dataset.read(frame_buffer, datatype, *memspace, dataspace);
}
void get_header_into(size_t frame_index, int part_index,
std::byte *header_buffer) {
seek(frame_index);
offset[1] = static_cast<hsize_t>(part_index);
// std::cout << "offset:" << ToString(offset) << " count:" <<
// ToString(count) << std::endl;
dataspace.selectHyperslab(H5S_SELECT_SET, count.data(), offset.data());
dataset.read(header_buffer, datatype, *memspace, dataspace);
}
private:
void intialize_dimensions() {
int rank = dataspace.getSimpleExtentNdims();
dims.resize(rank);
dataspace.getSimpleExtentDims(dims.data(), nullptr);
}
void initialize_memspace() {
int rank = dataspace.getSimpleExtentNdims();
count.clear();
offset.clear();
// header datasets or header virtual datasets
if (rank == 1 || rank == 2) {
count = std::vector<hsize_t>(rank, 1); // slice 1 value
offset = std::vector<hsize_t>(rank, 0);
memspace = std::make_unique<H5::DataSpace>(H5S_SCALAR);
} else if (rank >= 3) {
// data dataset (frame x height x width)
count = {1, dims[1], dims[2]};
offset = {0, 0, 0};
hsize_t dims_image[2] = {dims[1], dims[2]};
memspace = std::make_unique<H5::DataSpace>(2, dims_image);
} else {
throw std::runtime_error(
LOCATION + "Invalid rank for dataset: " + std::to_string(rank));
}
}
};
template <typename Fn>
void read_hdf5_header_fields(DetectorHeader *header, Fn &&fn_read_field) {
fn_read_field(0, reinterpret_cast<std::byte *>(&(header->frameNumber)));
fn_read_field(1, reinterpret_cast<std::byte *>(&(header->expLength)));
fn_read_field(2, reinterpret_cast<std::byte *>(&(header->packetNumber)));
fn_read_field(3, reinterpret_cast<std::byte *>(&(header->bunchId)));
fn_read_field(4, reinterpret_cast<std::byte *>(&(header->timestamp)));
fn_read_field(5, reinterpret_cast<std::byte *>(&(header->modId)));
fn_read_field(6, reinterpret_cast<std::byte *>(&(header->row)));
fn_read_field(7, reinterpret_cast<std::byte *>(&(header->column)));
fn_read_field(8, reinterpret_cast<std::byte *>(&(header->reserved)));
fn_read_field(9, reinterpret_cast<std::byte *>(&(header->debug)));
fn_read_field(10, reinterpret_cast<std::byte *>(&(header->roundRNumber)));
fn_read_field(11, reinterpret_cast<std::byte *>(&(header->detType)));
fn_read_field(12, reinterpret_cast<std::byte *>(&(header->version)));
fn_read_field(13, reinterpret_cast<std::byte *>(&(header->packetMask)));
}
/**
* @brief Class to read .h5 files. The class will parse the master file
* to find the correct geometry for the frames.
* @note A more generic interface is available in the aare::File class.
* Consider using that unless you need hdf5 file specific functionality.
*/
class Hdf5File : public FileInterface {
Hdf5MasterFile m_master;
size_t m_current_frame{};
size_t m_total_frames{};
size_t m_rows{};
size_t m_cols{};
static const std::string metadata_group_name;
static const std::vector<std::string> header_dataset_names;
std::unique_ptr<H5Handles> m_data_dataset{nullptr};
std::vector<std::unique_ptr<H5Handles>> m_header_datasets{};
public:
/**
* @brief Hdf5File constructor
* @param fname path to the master file (.json)
* @param mode file mode (only "r" is supported at the moment)
*/
Hdf5File(const std::filesystem::path &fname, const std::string &mode = "r");
virtual ~Hdf5File() override;
Frame read_frame() override;
Frame read_frame(size_t frame_number) override;
std::vector<Frame> read_n(size_t n_frames) override;
void read_into(std::byte *image_buf) override;
void read_into(std::byte *image_buf, size_t n_frames) override;
// TODO! do we need to adapt the API?
void read_into(std::byte *image_buf, DetectorHeader *header);
void read_into(std::byte *image_buf, size_t n_frames,
DetectorHeader *header);
size_t frame_number(size_t frame_index) override;
size_t bytes_per_frame() override;
size_t pixels_per_frame() override;
size_t bytes_per_pixel() const;
void seek(size_t frame_index) override;
size_t tell() override;
size_t total_frames() const override;
size_t rows() const override;
size_t cols() const override;
size_t bitdepth() const override;
xy geometry();
size_t n_modules() const;
Hdf5MasterFile master() const;
DetectorType detector_type() const override;
private:
/**
* @brief get the frame at the given frame index
* @param frame_number frame number to read
* @return Frame
*/
Frame get_frame(size_t frame_index);
/**
* @brief read the frame at the given frame index into the image buffer
* @param frame_number frame number to read
* @param n_frames number of frames to read (default is 1)
* @param image_buf buffer to store the frame
*/
void get_frame_into(size_t frame_index, std::byte *frame_buffer,
size_t n_frames = 1, DetectorHeader *header = nullptr);
/**
* @brief read the frame at the given frame index into the image buffer
* @param frame_index frame number to read
* @param n_frames number of frames to read (default is 1)
* @param frame_buffer buffer to store the frame
*/
void get_data_into(size_t frame_index, std::byte *frame_buffer,
size_t n_frames = 1);
/**
* @brief read the header at the given frame index into the header buffer
* @param frame_index frame number to read
* @param part_index part index to read (for virtual datasets)
* @param header buffer to store the header
*/
void get_header_into(size_t frame_index, int part_index,
DetectorHeader *header);
/**
* @brief read the header of the file
* @param fname path to the data subfile
* @return DetectorHeader
*/
static DetectorHeader read_header(const std::filesystem::path &fname);
void open_data_file();
void open_header_files();
};
} // namespace aare

View File

@ -1,135 +0,0 @@
#pragma once
#include "aare/defs.hpp"
#include "aare/scan_parameters.hpp"
#include "H5Cpp.h"
#include <filesystem>
#include <fmt/format.h>
#include <fstream>
#include <optional>
namespace aare {
using ns = std::chrono::nanoseconds;
/**
* @brief Class for parsing a master file either in our .json format or the old
* .Hdf5 format
*/
class Hdf5MasterFile {
std::filesystem::path m_file_name{};
std::string m_version;
DetectorType m_type;
TimingMode m_timing_mode;
xy m_geometry{};
int m_image_size_in_bytes{};
int m_pixels_y{};
int m_pixels_x{};
int m_max_frames_per_file{};
FrameDiscardPolicy m_frame_discard_policy{};
int m_frame_padding{};
std::optional<ScanParameters> m_scan_parameters{};
size_t m_total_frames_expected{};
std::optional<ns> m_exptime{};
std::optional<ns> m_period{};
std::optional<BurstMode> m_burst_mode{};
std::optional<int> m_number_of_udp_interfaces{};
int m_bitdepth{};
std::optional<bool> m_ten_giga{};
std::optional<int> m_threshold_energy{};
std::optional<std::vector<int>> m_threshold_energy_all{};
std::optional<ns> m_subexptime{};
std::optional<ns> m_subperiod{};
std::optional<bool> m_quad{};
std::optional<int> m_number_of_rows{};
std::optional<std::vector<size_t>> m_rate_corrections{};
std::optional<uint32_t> m_adc_mask{};
bool m_analog_flag{};
std::optional<int> m_analog_samples{};
bool m_digital_flag{};
std::optional<int> m_digital_samples{};
std::optional<int> m_dbit_offset{};
std::optional<size_t> m_dbit_list{};
std::optional<int> m_transceiver_mask{};
bool m_transceiver_flag{};
std::optional<int> m_transceiver_samples{};
// g1 roi - will not be implemented?
std::optional<ROI> m_roi{};
std::optional<int> m_counter_mask{};
std::optional<std::vector<ns>> m_exptime_array{};
std::optional<std::vector<ns>> m_gate_delay_array{};
std::optional<int> m_gates{};
std::optional<std::map<std::string, std::string>>
m_additional_json_header{};
size_t m_frames_in_file{};
// TODO! should these be bool?
public:
Hdf5MasterFile(const std::filesystem::path &fpath);
std::filesystem::path file_name() const;
const std::string &version() const; //!< For example "7.2"
const DetectorType &detector_type() const;
const TimingMode &timing_mode() const;
xy geometry() const;
int image_size_in_bytes() const;
int pixels_y() const;
int pixels_x() const;
int max_frames_per_file() const;
const FrameDiscardPolicy &frame_discard_policy() const;
int frame_padding() const;
std::optional<ScanParameters> scan_parameters() const;
size_t total_frames_expected() const;
std::optional<ns> exptime() const;
std::optional<ns> period() const;
std::optional<BurstMode> burst_mode() const;
std::optional<int> number_of_udp_interfaces() const;
int bitdepth() const;
std::optional<bool> ten_giga() const;
std::optional<int> threshold_energy() const;
std::optional<std::vector<int>> threshold_energy_all() const;
std::optional<ns> subexptime() const;
std::optional<ns> subperiod() const;
std::optional<bool> quad() const;
std::optional<int> number_of_rows() const;
std::optional<std::vector<size_t>> rate_corrections() const;
std::optional<uint32_t> adc_mask() const;
bool analog_flag() const;
std::optional<int> analog_samples() const;
bool digital_flag() const;
std::optional<int> digital_samples() const;
std::optional<int> dbit_offset() const;
std::optional<size_t> dbit_list() const;
std::optional<int> transceiver_mask() const;
bool transceiver_flag() const;
std::optional<int> transceiver_samples() const;
// g1 roi - will not be implemented?
std::optional<ROI> roi() const;
std::optional<int> counter_mask() const;
std::optional<std::vector<ns>> exptime_array() const;
std::optional<std::vector<ns>> gate_delay_array() const;
std::optional<int> gates() const;
std::optional<std::map<std::string, std::string>>
additional_json_header() const;
size_t frames_in_file() const;
size_t n_modules() const;
private:
static const std::string metadata_group_name;
void parse_acquisition_metadata(const std::filesystem::path &fpath);
template <typename T>
T h5_read_scalar_dataset(const H5::DataSet &dataset,
const H5::DataType &data_type);
template <typename T>
T h5_get_scalar_dataset(const H5::H5File &file,
const std::string &dataset_name);
};
template <>
std::string Hdf5MasterFile::h5_read_scalar_dataset<std::string>(
const H5::DataSet &dataset, const H5::DataType &data_type);
} // namespace aare

View File

@ -1,7 +1,5 @@
#pragma once
#include "aare/defs.hpp"
#include "aare/scan_parameters.hpp"
#include <filesystem>
#include <fmt/format.h>
#include <fstream>
@ -41,6 +39,28 @@ class RawFileNameComponents {
void set_old_scheme(bool old_scheme);
};
class ScanParameters {
bool m_enabled = false;
std::string m_dac;
int m_start = 0;
int m_stop = 0;
int m_step = 0;
// TODO! add settleTime, requires string to time conversion
public:
ScanParameters(const std::string &par);
ScanParameters() = default;
ScanParameters(const ScanParameters &) = default;
ScanParameters &operator=(const ScanParameters &) = default;
ScanParameters(ScanParameters &&) = default;
int start() const;
int stop() const;
int step() const;
const std::string &dac() const;
bool enabled() const;
void increment_stop();
};
/**
* @brief Class for parsing a master file either in our .json format or the old
* .raw format

View File

@ -1,15 +1,11 @@
#pragma once
#include "aare/Dtype.hpp"
#include "aare/type_traits.hpp"
#include <algorithm>
#include <array>
#include <cassert>
#include <cstdint>
#include <cstring>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <string_view>
@ -250,12 +246,17 @@ enum class DetectorType {
enum class TimingMode { Auto, Trigger };
enum class FrameDiscardPolicy { NoDiscard, Discard, DiscardPartial };
enum class BurstMode {
Burst_Interal,
Burst_External,
Continuous_Internal,
Continuous_External
};
template <class T> T StringTo(const std::string &arg) { return T(arg); }
template <class T> std::string ToString(T arg) { return T(arg); }
template <> DetectorType StringTo(const std::string & /*name*/);
template <> std::string ToString(DetectorType arg);
template <> TimingMode StringTo(const std::string & /*mode*/);
template <> FrameDiscardPolicy StringTo(const std::string & /*mode*/);
using DataTypeVariants = std::variant<uint16_t, uint32_t>;

View File

@ -1,51 +0,0 @@
#pragma once
#include <string>
#include <sstream>
namespace aare {
class ScanParameters {
bool m_enabled = false;
std::string m_dac;
int m_start = 0;
int m_stop = 0;
int m_step = 0;
// ns m_dac_settle_time{0};
// TODO! add settleTime, requires string to time conversion
public:
// "[enabled\ndac dac 4\nstart 500\nstop 2200\nstep 5\nsettleTime 100us\n]"
// TODO: use StringTo<ScanParameters> and move this to to_string
// add ways of setting the members of the class
ScanParameters(const std::string &par) {
std::istringstream iss(par.substr(1, par.size() - 2));
std::string line;
while (std::getline(iss, line)) {
if (line == "enabled") {
m_enabled = true;
} else if (line.find("dac") != std::string::npos) {
m_dac = line.substr(4);
} else if (line.find("start") != std::string::npos) {
m_start = std::stoi(line.substr(6));
} else if (line.find("stop") != std::string::npos) {
m_stop = std::stoi(line.substr(5));
} else if (line.find("step") != std::string::npos) {
m_step = std::stoi(line.substr(5));
}
}
};
ScanParameters() = default;
ScanParameters(const ScanParameters &) = default;
ScanParameters &operator=(const ScanParameters &) = default;
ScanParameters(ScanParameters &&) = default;
int start() const { return m_start; };
int stop() const { return m_stop; };
int step() const { return m_step; };
const std::string &dac() const { return m_dac; };
bool enabled() const { return m_enabled; };
void increment_stop() { m_stop += 1; };
};
} // namespace aare

View File

@ -1,11 +0,0 @@
#pragma once
#include <string>
namespace aare {
std::string RemoveUnit(std::string &str);
void TrimWhiteSpaces(std::string &s);
} // namespace aare

View File

@ -1,288 +0,0 @@
#pragma once
#include "aare/defs.hpp"
#include "aare/scan_parameters.hpp"
#include "aare/string_utils.hpp"
#include <optional>
#include <chrono>
namespace aare {
// generic
template <class T, typename = std::enable_if_t<!is_duration<T>::value>>
std::string ToString(T arg) {
return T(arg);
}
template <typename T,
std::enable_if_t<!is_duration<T>::value && !is_container<T>::value,
int> = 0>
T StringTo(const std::string &arg) {
return T(arg);
}
// time
/** Convert std::chrono::duration with specified output unit */
template <typename T, typename Rep = double>
typename std::enable_if<is_duration<T>::value, std::string>::type
ToString(T t, const std::string &unit) {
using std::chrono::duration;
using std::chrono::duration_cast;
std::ostringstream os;
if (unit == "ns")
os << duration_cast<duration<Rep, std::nano>>(t).count() << unit;
else if (unit == "us")
os << duration_cast<duration<Rep, std::micro>>(t).count() << unit;
else if (unit == "ms")
os << duration_cast<duration<Rep, std::milli>>(t).count() << unit;
else if (unit == "s")
os << duration_cast<duration<Rep>>(t).count() << unit;
else
throw std::runtime_error("Unknown unit: " + unit);
return os.str();
}
/** Convert std::chrono::duration automatically selecting the unit */
template <typename From>
typename std::enable_if<is_duration<From>::value, std::string>::type
ToString(From t) {
using std::chrono::abs;
using std::chrono::duration_cast;
using std::chrono::microseconds;
using std::chrono::milliseconds;
using std::chrono::nanoseconds;
auto tns = duration_cast<nanoseconds>(t);
if (abs(tns) < microseconds(1)) {
return ToString(tns, "ns");
} else if (abs(tns) < milliseconds(1)) {
return ToString(tns, "us");
} else if (abs(tns) < milliseconds(99)) {
return ToString(tns, "ms");
} else {
return ToString(tns, "s");
}
}
template <class Rep, class Period>
std::ostream &operator<<(std::ostream &os,
const std::chrono::duration<Rep, Period> &d) {
return os << ToString(d);
}
template <typename T>
T StringTo(const std::string &t, const std::string &unit) {
double tval{0};
try {
tval = std::stod(t);
} catch (const std::invalid_argument &e) {
throw std::invalid_argument("[ERROR] Could not convert string to time");
}
using std::chrono::duration;
using std::chrono::duration_cast;
if (unit == "ns") {
return duration_cast<T>(duration<double, std::nano>(tval));
} else if (unit == "us") {
return duration_cast<T>(duration<double, std::micro>(tval));
} else if (unit == "ms") {
return duration_cast<T>(duration<double, std::milli>(tval));
} else if (unit == "s" || unit.empty()) {
return duration_cast<T>(std::chrono::duration<double>(tval));
} else {
throw std::invalid_argument("[ERROR] Invalid unit in conversion from "
"string to std::chrono::duration");
}
}
template <typename T, std::enable_if_t<is_duration<T>::value, int> = 0>
T StringTo(const std::string &t) {
std::string tmp{t};
auto unit = RemoveUnit(tmp);
return StringTo<T>(tmp, unit);
}
template <> inline bool StringTo(const std::string &s) {
int i = std::stoi(s, nullptr, 10);
switch (i) {
case 0:
return false;
case 1:
return true;
default:
throw std::runtime_error("Unknown boolean. Expecting be 0 or 1.");
}
}
template <> inline uint8_t StringTo(const std::string &s) {
int base = s.find("0x") != std::string::npos ? 16 : 10;
int value = std::stoi(s, nullptr, base);
if (value < std::numeric_limits<uint8_t>::min() ||
value > std::numeric_limits<uint8_t>::max()) {
throw std::runtime_error("Cannot scan uint8_t from string '" + s +
"'. Value must be in range 0 - 255.");
}
return static_cast<uint8_t>(value);
}
template <> inline uint16_t StringTo(const std::string &s) {
int base = s.find("0x") != std::string::npos ? 16 : 10;
int value = std::stoi(s, nullptr, base);
if (value < std::numeric_limits<uint16_t>::min() ||
value > std::numeric_limits<uint16_t>::max()) {
throw std::runtime_error("Cannot scan uint16_t from string '" + s +
"'. Value must be in range 0 - 65535.");
}
return static_cast<uint16_t>(value);
}
template <> inline uint32_t StringTo(const std::string &s) {
int base = s.find("0x") != std::string::npos ? 16 : 10;
return std::stoul(s, nullptr, base);
}
template <> inline uint64_t StringTo(const std::string &s) {
int base = s.find("0x") != std::string::npos ? 16 : 10;
return std::stoull(s, nullptr, base);
}
template <> inline int StringTo(const std::string &s) {
int base = s.find("0x") != std::string::npos ? 16 : 10;
return std::stoi(s, nullptr, base);
}
/*template <> inline size_t StringTo(const std::string &s) {
int base = s.find("0x") != std::string::npos ? 16 : 10;
return std::stoull(s, nullptr, base);
}*/
// vector
template <typename T> std::string ToString(const std::vector<T> &vec) {
std::ostringstream oss;
oss << "[";
for (size_t i = 0; i < vec.size(); ++i) {
oss << vec[i];
if (i != vec.size() - 1)
oss << ", ";
}
oss << "]";
return oss.str();
}
template <typename T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &v) {
return os << ToString(v);
}
template <typename Container,
std::enable_if_t<is_container<Container>::value &&
!is_std_string_v<Container> /*&&
!is_map_v<Container>*/
,
int> = 0>
Container StringTo(const std::string &s) {
using Value = typename Container::value_type;
// strip outer brackets
std::string str = s;
str.erase(
std::remove_if(str.begin(), str.end(),
[](unsigned char c) { return c == '[' || c == ']'; }),
str.end());
std::stringstream ss(str);
std::string item;
Container result;
while (std::getline(ss, item, ',')) {
TrimWhiteSpaces(item);
if (!item.empty()) {
result.push_back(StringTo<Value>(item));
}
}
return result;
}
// map
template <typename KeyType, typename ValueType>
std::string ToString(const std::map<KeyType, ValueType> &m) {
std::ostringstream os;
os << '{';
if (!m.empty()) {
auto it = m.cbegin();
os << ToString(it->first) << ": " << ToString(it->second);
it++;
while (it != m.cend()) {
os << ", " << ToString(it->first) << ": " << ToString(it->second);
it++;
}
}
os << '}';
return os.str();
}
template <>
inline std::map<std::string, std::string> StringTo(const std::string &s) {
std::map<std::string, std::string> result;
std::string str = s;
// Remove outer braces if present
if (!str.empty() && str.front() == '{' && str.back() == '}') {
str = str.substr(1, str.size() - 2);
}
std::stringstream ss(str);
std::string item;
while (std::getline(ss, item, ',')) {
auto colon_pos = item.find(':');
if (colon_pos == std::string::npos)
throw std::runtime_error("Missing ':' in item: " + item);
std::string key = item.substr(0, colon_pos);
std::string value = item.substr(colon_pos + 1);
TrimWhiteSpaces(key);
TrimWhiteSpaces(value);
result[key] = value;
}
return result;
}
// optional
template <class T> std::string ToString(const std::optional<T> &opt) {
return opt ? ToString(*opt) : "nullopt";
}
template <typename T>
std::ostream &operator<<(std::ostream &os, const std::optional<T> &opt) {
if (opt)
os << *opt;
else
os << "nullopt";
return os;
}
// enums
template <> std::string ToString(DetectorType arg);
template <> DetectorType StringTo(const std::string & /*name*/);
template <> std::string ToString(TimingMode arg);
template <> TimingMode StringTo(const std::string & /*mode*/);
template <> std::string ToString(FrameDiscardPolicy arg);
template <> FrameDiscardPolicy StringTo(const std::string & /*mode*/);
template <> std::string ToString(BurstMode arg);
template <> BurstMode StringTo(const std::string & /*mode*/);
template <> std::string ToString(ROI arg);
std::ostream &operator<<(std::ostream &os, const ROI &roi);
template <> std::string ToString(ScanParameters arg);
std::ostream &operator<<(std::ostream &os, const ScanParameters &r);
} // namespace aare

View File

@ -1,72 +0,0 @@
#pragma once
#include <type_traits>
namespace aare {
/**
* Type trait to check if a template parameter is a std::chrono::duration
*/
template <typename T, typename _ = void>
struct is_duration : std::false_type {};
template <typename... Ts> struct is_duration_helper {};
template <typename T>
struct is_duration<T,
typename std::conditional<
false,
is_duration_helper<typename T::rep, typename T::period,
decltype(std::declval<T>().min()),
decltype(std::declval<T>().max()),
decltype(std::declval<T>().zero())>,
void>::type> : public std::true_type {};
/**
* Type trait to evaluate if template parameter is
* complying with a standard container
*/
template <typename T, typename _ = void>
struct is_container : std::false_type {};
template <typename... Ts> struct is_container_helper {};
template <typename T>
struct is_container<
T, typename std::conditional<
false,
is_container_helper<
typename std::remove_reference<T>::type::value_type,
typename std::remove_reference<T>::type::size_type,
typename std::remove_reference<T>::type::iterator,
typename std::remove_reference<T>::type::const_iterator,
decltype(std::declval<T>().size()),
decltype(std::declval<T>().begin()),
decltype(std::declval<T>().end()),
decltype(std::declval<T>().cbegin()),
decltype(std::declval<T>().cend()),
decltype(std::declval<T>().empty())>,
void>::type> : public std::true_type {};
/**
* Type trait to evaluate if template parameter is
* complying with a std::string
*/
template <typename T>
inline constexpr bool is_std_string_v =
std::is_same_v<std::decay_t<T>, std::string>;
/**
* Type trait to evaluate if template parameter is
* complying with std::map
*/
template <typename T> struct is_map : std::false_type {};
template <typename K, typename V, typename... Args>
struct is_map<std::map<K, V, Args...>> : std::true_type {};
template <typename T>
inline constexpr bool is_map_v = is_map<std::decay_t<T>>::value;
} // namespace aare

View File

@ -1,16 +1,8 @@
# from ._aare import ClusterFinder_Cluster3x3i, ClusterFinder_Cluster2x2i, ClusterFinderMT_Cluster3x3i, ClusterFinderMT_Cluster2x2i, ClusterCollector_Cluster3x3i, ClusterCollector_Cluster2x2i
# from ._aare import ClusterFileSink_Cluster3x3i, ClusterFileSink_Cluster2x2i
from . import _aare
import numpy as np
_supported_cluster_sizes = [(2,2), (3,3), (5,5), (7,7), (9,9),]
# def _get_class()
def _type_to_char(dtype):
if dtype == np.int32:
return 'i'
@ -74,11 +66,22 @@ def ClusterFileSink(clusterfindermt, cluster_file, dtype=np.int32):
return cls(clusterfindermt, cluster_file)
def ClusterFile(fname, cluster_size=(3,3), dtype=np.int32):
def ClusterFile(fname, cluster_size=(3,3), dtype=np.int32, chunk_size = 1000):
"""
Factory function to create a ClusterFile object. Provides a cleaner syntax for
the templated ClusterFile in C++.
.. code-block:: python
from aare import ClusterFile
with ClusterFile("clusters.clust", cluster_size=(3,3), dtype=np.int32) as cf:
# cf is now a ClusterFile_Cluster3x3i object but you don't need to know that.
for clusters in cf:
# Loop over clusters in chunks of 1000
# The type of clusters will be a ClusterVector_Cluster3x3i in this case
"""
cls = _get_class("ClusterFile", cluster_size, dtype)
return cls(fname)
return cls(fname, chunk_size=chunk_size)

View File

@ -1,66 +0,0 @@
from . import _aare
import numpy as np
#from .ScanParameters import ScanParameters
class Hdf5File(_aare.Hdf5File):
def __init__(self, fname, chunk_size = 1):
super().__init__(fname)
self._chunk_size = chunk_size
def read(self) -> tuple:
"""Read the entire file.
Seeks to the beginning of the file before reading.
Returns:
tuple: header, data
"""
self.seek(0)
return self.read_n(self.total_frames)
# @property
# def scan_parameters(self):
# """Return the scan parameters.
# Returns:
# ScanParameters: Scan parameters.
# """
# return ScanParameters(self.master.scan_parameters)
@property
def master(self):
"""Return the master file.
Returns:
Hdf5MasterFile: Master file.
"""
return super().master
def __len__(self) -> int:
"""Return the number of frames in the file.
Returns:
int: Number of frames in file.
"""
return super().frames_in_file
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
pass
def __iter__(self):
return self
def __next__(self):
try:
if self._chunk_size == 1:
return self.read_frame()
else:
return self.read_n(self._chunk_size)
except RuntimeError:
# TODO! find a good way to check that we actually have the right exception
raise StopIteration

View File

@ -2,7 +2,7 @@
from . import _aare
from ._aare import File, RawMasterFile, RawSubFile, Hdf5MasterFile, JungfrauDataFile
from ._aare import File, RawMasterFile, RawSubFile, JungfrauDataFile
from ._aare import Pedestal_d, Pedestal_f, ClusterFinder_Cluster3x3i, VarClusterFinder
from ._aare import DetectorType
from ._aare import hitmap
@ -23,7 +23,6 @@ from ._aare import apply_custom_weights
from .CtbRawFile import CtbRawFile
from .RawFile import RawFile
from .Hdf5File import Hdf5File
from .ScanParameters import ScanParameters
from .utils import random_pixels, random_pixel, flat_list, add_colorbar

View File

@ -38,19 +38,20 @@ void define_ClusterFile(py::module &m, const std::string &typestr) {
self.read_clusters(n_clusters));
return v;
},
py::return_value_policy::take_ownership)
py::return_value_policy::take_ownership, py::arg("n_clusters"))
.def("read_frame",
[](ClusterFile<ClusterType> &self) {
auto v = new ClusterVector<ClusterType>(self.read_frame());
return v;
})
.def("set_roi", &ClusterFile<ClusterType>::set_roi)
.def("set_roi", &ClusterFile<ClusterType>::set_roi,
py::arg("roi"))
.def(
"set_noise_map",
[](ClusterFile<ClusterType> &self, py::array_t<int32_t> noise_map) {
auto view = make_view_2d(noise_map);
self.set_noise_map(view);
})
}, py::arg("noise_map"))
.def("set_gain_map",
[](ClusterFile<ClusterType> &self, py::array_t<double> gain_map) {

View File

@ -5,11 +5,6 @@
#include "aare/RawMasterFile.hpp"
#include "aare/RawSubFile.hpp"
#ifdef HDF5_FOUND
#include "aare/Hdf5File.hpp"
#include "aare/Hdf5MasterFile.hpp"
#endif
#include "aare/defs.hpp"
// #include "aare/fClusterFileV2.hpp"

View File

@ -1,106 +0,0 @@
#include "H5Cpp.h"
#include "aare/File.hpp"
#include "aare/Frame.hpp"
#include "aare/Hdf5File.hpp"
#include "aare/Hdf5MasterFile.hpp"
#include "aare/defs.hpp"
// #include "aare/fClusterFileV2.hpp"
#include <cstdint>
#include <filesystem>
#include <pybind11/iostream.h>
#include <pybind11/numpy.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/stl/filesystem.h>
#include <string>
namespace py = pybind11;
using namespace ::aare;
void define_hdf5_file_io_bindings(py::module &m) {
py::class_<Hdf5File>(m, "Hdf5File")
.def(py::init<const std::filesystem::path &>())
.def("read_frame",
[](Hdf5File &self) {
py::array image;
std::vector<ssize_t> shape;
shape.reserve(2);
shape.push_back(self.rows());
shape.push_back(self.cols());
// return headers from all subfiles
py::array_t<DetectorHeader> header(self.n_mod());
const uint8_t item_size = self.bytes_per_pixel();
if (item_size == 1) {
image = py::array_t<uint8_t>(shape);
} else if (item_size == 2) {
image = py::array_t<uint16_t>(shape);
} else if (item_size == 4) {
image = py::array_t<uint32_t>(shape);
}
self.read_into(
reinterpret_cast<std::byte *>(image.mutable_data()),
header.mutable_data());
return py::make_tuple(header, image);
})
.def(
"read_n",
[](Hdf5File &self, size_t n_frames) {
// adjust for actual frames left in the file
n_frames =
std::min(n_frames, self.total_frames() - self.tell());
if (n_frames == 0) {
throw std::runtime_error("No frames left in file");
}
std::vector<size_t> shape{n_frames, self.rows(), self.cols()};
// return headers from all subfiles
py::array_t<DetectorHeader> header;
if (self.n_mod() == 1) {
header = py::array_t<DetectorHeader>(n_frames);
} else {
header =
py::array_t<DetectorHeader>({self.n_mod(), n_frames});
}
// py::array_t<DetectorHeader> header({self.n_mod(), n_frames});
py::array image;
const uint8_t item_size = self.bytes_per_pixel();
if (item_size == 1) {
image = py::array_t<uint8_t>(shape);
} else if (item_size == 2) {
image = py::array_t<uint16_t>(shape);
} else if (item_size == 4) {
image = py::array_t<uint32_t>(shape);
}
self.read_into(
reinterpret_cast<std::byte *>(image.mutable_data()),
n_frames, header.mutable_data());
return py::make_tuple(header, image);
},
R"(
Read n frames from the file.
)")
.def("frame_number", &Hdf5File::frame_number)
.def_property_readonly("bytes_per_frame", &Hdf5File::bytes_per_frame)
.def_property_readonly("pixels_per_frame", &Hdf5File::pixels_per_frame)
.def_property_readonly("bytes_per_pixel", &Hdf5File::bytes_per_pixel)
.def("seek", &Hdf5File::seek, R"(
Seek to a frame index in file.
)")
.def("tell", &Hdf5File::tell, R"(
Return the current frame number.)")
.def_property_readonly("total_frames", &Hdf5File::total_frames)
.def_property_readonly("rows", &Hdf5File::rows)
.def_property_readonly("cols", &Hdf5File::cols)
.def_property_readonly("bitdepth", &Hdf5File::bitdepth)
.def_property_readonly("geometry", &Hdf5File::geometry)
.def_property_readonly("n_mod", &Hdf5File::n_mod)
.def_property_readonly("detector_type", &Hdf5File::detector_type)
.def_property_readonly("master", &Hdf5File::master);
}

View File

@ -1,86 +0,0 @@
#include "aare/File.hpp"
#include "aare/Frame.hpp"
#include "aare/Hdf5File.hpp"
#include "aare/Hdf5MasterFile.hpp"
#include "aare/defs.hpp"
// #include "aare/fClusterFileV2.hpp"
#include <cstdint>
#include <filesystem>
#include <pybind11/iostream.h>
#include <pybind11/numpy.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/stl/filesystem.h>
#include <string>
namespace py = pybind11;
using namespace ::aare;
void define_hdf5_master_file_bindings(py::module &m) {
py::class_<Hdf5MasterFile>(m, "Hdf5MasterFile")
.def(py::init<const std::filesystem::path &>())
.def("data_fname", &Hdf5MasterFile::data_fname, R"(
Parameters
------------
module_index : int
module index (d0, d1 .. dN)
file_index : int
file index (f0, f1 .. fN)
Returns
----------
os.PathLike
The name of the data file.
)")
.def_property_readonly("version", &Hdf5MasterFile::version)
.def_property_readonly("detector_type", &Hdf5MasterFile::detector_type)
.def_property_readonly("timing_mode", &Hdf5MasterFile::timing_mode)
.def_property_readonly("image_size_in_bytes",
&Hdf5MasterFile::image_size_in_bytes)
.def_property_readonly("frames_in_file",
&Hdf5MasterFile::frames_in_file)
.def_property_readonly("pixels_y", &Hdf5MasterFile::pixels_y)
.def_property_readonly("pixels_x", &Hdf5MasterFile::pixels_x)
.def_property_readonly("max_frames_per_file",
&Hdf5MasterFile::max_frames_per_file)
.def_property_readonly("bitdepth", &Hdf5MasterFile::bitdepth)
.def_property_readonly("frame_padding", &Hdf5MasterFile::frame_padding)
.def_property_readonly("frame_discard_policy",
&Hdf5MasterFile::frame_discard_policy)
.def_property_readonly("total_frames_expected",
&Hdf5MasterFile::total_frames_expected)
.def_property_readonly("geometry", &Hdf5MasterFile::geometry)
.def_property_readonly("analog_samples",
&Hdf5MasterFile::analog_samples, R"(
Number of analog samples
Returns
----------
int | None
The number of analog samples in the file (or None if not enabled)
)")
.def_property_readonly("digital_samples",
&Hdf5MasterFile::digital_samples, R"(
Number of digital samples
Returns
----------
int | None
The number of digital samples in the file (or None if not enabled)
)")
.def_property_readonly("transceiver_samples",
&Hdf5MasterFile::transceiver_samples)
.def_property_readonly("number_of_rows",
&Hdf5MasterFile::number_of_rows)
.def_property_readonly("quad", &Hdf5MasterFile::quad);
//.def_property_readonly("scan_parameters",
// &Hdf5MasterFile::scan_parameters)
//.def_property_readonly("roi", &Hdf5MasterFile::roi);
}

View File

@ -14,10 +14,6 @@
#include "file.hpp"
#include "fit.hpp"
#include "interpolation.hpp"
#ifdef HDF5_FOUND
#include "hdf5_file.hpp"
#include "hdf5_master_file.hpp"
#endif
#include "jungfrau_data_file.hpp"
#include "pedestal.hpp"
#include "pixel_map.hpp"
@ -58,10 +54,6 @@ PYBIND11_MODULE(_aare, m) {
define_raw_sub_file_io_bindings(m);
define_ctb_raw_file_io_bindings(m);
define_raw_master_file_bindings(m);
#ifdef HDF5_FOUND
define_hdf5_file_io_bindings(m);
define_hdf5_master_file_bindings(m);
#endif
define_var_cluster_finder_bindings(m);
define_pixel_map_bindings(m);
define_pedestal_bindings<double>(m, "Pedestal_d");

View File

@ -1,7 +1,4 @@
#include "aare/File.hpp"
#ifdef HDF5_FOUND
#include "aare/Hdf5File.hpp"
#endif
#include "aare/JungfrauDataFile.hpp"
#include "aare/NumpyFile.hpp"
#include "aare/RawFile.hpp"
@ -30,17 +27,7 @@ File::File(const std::filesystem::path &fname, const std::string &mode,
} else if (fname.extension() == ".npy") {
// file_impl = new NumpyFile(fname, mode, cfg);
file_impl = std::make_unique<NumpyFile>(fname, mode, cfg);
}
#ifdef HDF5_FOUND
else if (fname.extension() == ".h5") {
file_impl = std::make_unique<Hdf5File>(fname, mode);
}
#else
else if (fname.extension() == ".h5") {
throw std::runtime_error("Enable HDF5 compile option: AARE_HDF5=ON");
}
#endif
else if (fname.extension() == ".dat") {
} else if (fname.extension() == ".dat") {
file_impl = std::make_unique<JungfrauDataFile>(fname);
} else {
throw std::runtime_error("Unsupported file type");

View File

@ -1,234 +0,0 @@
#include "aare/Hdf5File.hpp"
#include "aare/PixelMap.hpp"
#include "aare/defs.hpp"
#include "aare/logger.hpp"
#include <fmt/format.h>
namespace aare {
Hdf5File::Hdf5File(const std::filesystem::path &fname, const std::string &mode)
: m_master(fname) {
m_mode = mode;
if (mode == "r") {
open_data_file();
open_header_files();
} else {
throw std::runtime_error(LOCATION +
"Unsupported mode. Can only read Hdf5Files.");
}
}
Frame Hdf5File::read_frame() { return get_frame(m_current_frame++); }
Frame Hdf5File::read_frame(size_t frame_number) {
seek(frame_number);
return read_frame();
}
std::vector<Frame> Hdf5File::read_n(size_t n_frames) {
// TODO: implement this in a more efficient way
std::vector<Frame> frames;
for (size_t i = 0; i < n_frames; i++) {
frames.push_back(this->get_frame(m_current_frame));
m_current_frame++;
}
return frames;
}
void Hdf5File::read_into(std::byte *image_buf, size_t n_frames) {
get_frame_into(m_current_frame++, image_buf, n_frames);
}
void Hdf5File::read_into(std::byte *image_buf) {
get_frame_into(m_current_frame++, image_buf);
}
void Hdf5File::read_into(std::byte *image_buf, DetectorHeader *header) {
get_frame_into(m_current_frame, image_buf, 1, header);
}
void Hdf5File::read_into(std::byte *image_buf, size_t n_frames,
DetectorHeader *header) {
get_frame_into(m_current_frame++, image_buf, n_frames, header);
}
size_t Hdf5File::frame_number(size_t frame_index) {
// TODO: check if it should check total_Frames() at any point
// check why this->read_into.. as in RawFile
// refactor multiple frame reads into a single one using hyperslab
if (frame_index >= m_master.frames_in_file()) {
throw std::runtime_error(LOCATION + " Frame number out of range");
}
uint64_t fnum{0};
int part_index = 0; // assuming first part
m_header_datasets[0]->get_header_into(frame_index, part_index,
reinterpret_cast<std::byte *>(&fnum));
return fnum;
}
size_t Hdf5File::bytes_per_frame() {
return m_rows * m_cols * m_master.bitdepth() / 8;
}
size_t Hdf5File::pixels_per_frame() { return m_rows * m_cols; }
size_t Hdf5File::bytes_per_pixel() const { return m_master.bitdepth() / 8; }
void Hdf5File::seek(size_t frame_index) {
m_data_dataset->seek(frame_index);
for (size_t i = 0; i != header_dataset_names.size(); ++i) {
m_header_datasets[i]->seek(frame_index);
}
m_current_frame = frame_index;
}
size_t Hdf5File::tell() { return m_current_frame; }
size_t Hdf5File::total_frames() const { return m_total_frames; }
size_t Hdf5File::rows() const { return m_rows; }
size_t Hdf5File::cols() const { return m_cols; }
size_t Hdf5File::bitdepth() const { return m_master.bitdepth(); }
xy Hdf5File::geometry() { return m_master.geometry(); }
size_t Hdf5File::n_modules() const { return m_master.n_modules(); }
Hdf5MasterFile Hdf5File::master() const { return m_master; }
DetectorType Hdf5File::detector_type() const {
return m_master.detector_type();
}
Frame Hdf5File::get_frame(size_t frame_index) {
auto f = Frame(m_rows, m_cols, Dtype::from_bitdepth(m_master.bitdepth()));
std::byte *frame_buffer = f.data();
get_frame_into(frame_index, frame_buffer);
return f;
}
void Hdf5File::get_frame_into(size_t frame_index, std::byte *frame_buffer,
size_t n_frames, DetectorHeader *header) {
if ((frame_index + n_frames - 1) >= m_master.frames_in_file()) {
throw std::runtime_error(LOCATION + "Frame number out of range");
}
get_data_into(frame_index, frame_buffer);
m_current_frame += n_frames;
if (header) {
for (size_t i = 0; i < n_frames; i++) {
for (size_t part_idx = 0; part_idx != m_master.n_modules();
++part_idx) {
get_header_into(frame_index + i, part_idx, header);
header++;
}
}
}
}
void Hdf5File::get_data_into(size_t frame_index, std::byte *frame_buffer,
size_t n_frames) {
m_data_dataset->get_data_into(frame_index, frame_buffer, n_frames);
}
void Hdf5File::get_header_into(size_t frame_index, int part_index,
DetectorHeader *header) {
try {
read_hdf5_header_fields(header, [&](size_t iParameter,
std::byte *dest) {
m_header_datasets[iParameter]->get_header_into(frame_index,
part_index, dest);
});
LOG(logDEBUG5) << "Read 1D header for frame " << frame_index;
} catch (const H5::Exception &e) {
fmt::print("Exception type: {}\n", typeid(e).name());
e.printErrorStack();
throw std::runtime_error(
LOCATION + "\nCould not to access header datasets in given file.");
}
}
DetectorHeader Hdf5File::read_header(const std::filesystem::path &fname) {
DetectorHeader h{};
std::vector<std::unique_ptr<H5Handles>> handles;
try {
for (size_t i = 0; i != header_dataset_names.size(); ++i) {
handles.push_back(std::make_unique<H5Handles>(
fname.string(), metadata_group_name + header_dataset_names[i]));
}
read_hdf5_header_fields(&h, [&](size_t iParameter, std::byte *dest) {
handles[iParameter]->get_header_into(0, 0, dest);
});
LOG(logDEBUG5) << "Read 1D header for frame 0";
} catch (const H5::Exception &e) {
handles.clear();
fmt::print("Exception type: {}\n", typeid(e).name());
e.printErrorStack();
throw std::runtime_error(
LOCATION + "\nCould not to access header datasets in given file.");
}
return h;
}
Hdf5File::~Hdf5File() {}
const std::string Hdf5File::metadata_group_name = "/entry/data/";
const std::vector<std::string> Hdf5File::header_dataset_names = {
"frame number",
"exp length or sub exposure time",
"packets caught",
"detector specific 1",
"timestamp",
"mod id",
"row",
"column",
"detector specific 2",
"detector specific 3",
"detector specific 4",
"detector type",
"detector header version",
"packets caught bit mask"};
void Hdf5File::open_data_file() {
if (m_mode != "r")
throw std::runtime_error(LOCATION +
"Unsupported mode. Can only read Hdf5 files.");
try {
m_data_dataset = std::make_unique<H5Handles>(
m_master.file_name().string(), metadata_group_name + "/data");
m_total_frames = m_data_dataset->get_dims()[0];
m_rows = m_data_dataset->get_dims()[1];
m_cols = m_data_dataset->get_dims()[2];
// fmt::print("Data Dataset dimensions: frames = {}, rows = {}, cols =
// {}\n",
// m_total_frames, m_rows, m_cols);
} catch (const H5::Exception &e) {
m_data_dataset.reset();
fmt::print("Exception type: {}\n", typeid(e).name());
e.printErrorStack();
throw std::runtime_error(
LOCATION + "\nCould not to access 'data' dataset in master file.");
}
}
void Hdf5File::open_header_files() {
if (m_mode != "r")
throw std::runtime_error(LOCATION +
"Unsupported mode. Can only read Hdf5 files.");
try {
for (size_t i = 0; i != header_dataset_names.size(); ++i) {
m_header_datasets.push_back(std::make_unique<H5Handles>(
m_master.file_name().string(),
metadata_group_name + header_dataset_names[i]));
LOG(logDEBUG) << header_dataset_names[i]
<< " Dataset dimensions: size = "
<< m_header_datasets[i]->get_dims()[0];
}
} catch (const H5::Exception &e) {
m_header_datasets.clear();
m_data_dataset.reset();
fmt::print("Exception type: {}\n", typeid(e).name());
e.printErrorStack();
throw std::runtime_error(
LOCATION + "\nCould not to access header datasets in master file.");
}
}
} // namespace aare

View File

View File

@ -1,565 +0,0 @@
#include "aare/Hdf5MasterFile.hpp"
#include "aare/logger.hpp"
#include "aare/to_string.hpp"
#include <iomanip>
#include <sstream>
namespace aare {
Hdf5MasterFile::Hdf5MasterFile(const std::filesystem::path &fpath)
: m_file_name(fpath) {
if (!std::filesystem::exists(fpath)) {
throw std::runtime_error(LOCATION + " File does not exist");
}
parse_acquisition_metadata(fpath);
}
std::filesystem::path Hdf5MasterFile::file_name() const {
return m_file_name;
}
const std::string &Hdf5MasterFile::version() const { return m_version; }
const DetectorType &Hdf5MasterFile::detector_type() const { return m_type; }
const TimingMode &Hdf5MasterFile::timing_mode() const { return m_timing_mode; }
xy Hdf5MasterFile::geometry() const { return m_geometry; }
int Hdf5MasterFile::image_size_in_bytes() const {
return m_image_size_in_bytes;
}
int Hdf5MasterFile::pixels_y() const { return m_pixels_y; }
int Hdf5MasterFile::pixels_x() const { return m_pixels_x; }
int Hdf5MasterFile::max_frames_per_file() const {
return m_max_frames_per_file;
}
const FrameDiscardPolicy &Hdf5MasterFile::frame_discard_policy() const {
return m_frame_discard_policy;
}
int Hdf5MasterFile::frame_padding() const { return m_frame_padding; }
std::optional<ScanParameters> Hdf5MasterFile::scan_parameters() const {
return m_scan_parameters;
}
size_t Hdf5MasterFile::total_frames_expected() const {
return m_total_frames_expected;
}
std::optional<ns> Hdf5MasterFile::exptime() const { return m_exptime; }
std::optional<ns> Hdf5MasterFile::period() const { return m_period; }
std::optional<BurstMode> Hdf5MasterFile::burst_mode() const {
return m_burst_mode;
}
std::optional<int> Hdf5MasterFile::number_of_udp_interfaces() const {
return m_number_of_udp_interfaces;
}
int Hdf5MasterFile::bitdepth() const { return m_bitdepth; }
std::optional<bool> Hdf5MasterFile::ten_giga() const { return m_ten_giga; }
std::optional<int> Hdf5MasterFile::threshold_energy() const {
return m_threshold_energy;
}
std::optional<std::vector<int>> Hdf5MasterFile::threshold_energy_all() const {
return m_threshold_energy_all;
}
std::optional<ns> Hdf5MasterFile::subexptime() const { return m_subexptime; }
std::optional<ns> Hdf5MasterFile::subperiod() const { return m_subperiod; }
std::optional<bool> Hdf5MasterFile::quad() const { return m_quad; }
std::optional<int> Hdf5MasterFile::number_of_rows() const {
return m_number_of_rows;
}
std::optional<std::vector<size_t>> Hdf5MasterFile::rate_corrections() const {
return m_rate_corrections;
}
std::optional<uint32_t> Hdf5MasterFile::adc_mask() const { return m_adc_mask; }
bool Hdf5MasterFile::analog_flag() const { return m_analog_flag; }
std::optional<int> Hdf5MasterFile::analog_samples() const {
return m_analog_samples;
}
bool Hdf5MasterFile::digital_flag() const { return m_digital_flag; }
std::optional<int> Hdf5MasterFile::digital_samples() const {
return m_digital_samples;
}
std::optional<int> Hdf5MasterFile::dbit_offset() const { return m_dbit_offset; }
std::optional<size_t> Hdf5MasterFile::dbit_list() const { return m_dbit_list; }
std::optional<int> Hdf5MasterFile::transceiver_mask() const {
return m_transceiver_mask;
}
bool Hdf5MasterFile::transceiver_flag() const { return m_transceiver_flag; }
std::optional<int> Hdf5MasterFile::transceiver_samples() const {
return m_transceiver_samples;
}
// g1 roi
std::optional<ROI> Hdf5MasterFile::roi() const { return m_roi; }
std::optional<int> Hdf5MasterFile::counter_mask() const {
return m_counter_mask;
}
std::optional<std::vector<ns>> Hdf5MasterFile::exptime_array() const {
return m_exptime_array;
}
std::optional<std::vector<ns>> Hdf5MasterFile::gate_delay_array() const {
return m_gate_delay_array;
}
std::optional<int> Hdf5MasterFile::gates() const { return m_gates; }
std::optional<std::map<std::string, std::string>>
Hdf5MasterFile::additional_json_header() const {
return m_additional_json_header;
}
size_t Hdf5MasterFile::frames_in_file() const { return m_frames_in_file; }
size_t Hdf5MasterFile::n_modules() const {
return m_geometry.row * m_geometry.col;
}
// optional values, these may or may not be present in the master file
// and are therefore modeled as std::optional
const std::string Hdf5MasterFile::metadata_group_name =
"/entry/instrument/detector/";
template <typename T>
T Hdf5MasterFile::h5_read_scalar_dataset(const H5::DataSet &dataset,
const H5::DataType &data_type) {
T value;
dataset.read(&value, data_type);
return value;
}
template <>
std::string Hdf5MasterFile::h5_read_scalar_dataset<std::string>(
const H5::DataSet &dataset, const H5::DataType &data_type) {
size_t size = data_type.getSize();
std::vector<char> buffer(size + 1, 0);
dataset.read(buffer.data(), data_type);
return std::string(buffer.data());
}
template <typename T>
T Hdf5MasterFile::h5_get_scalar_dataset(const H5::H5File &file,
const std::string &dataset_name) {
H5::DataSet dataset = file.openDataSet(dataset_name);
H5::DataSpace dataspace = dataset.getSpace();
if (dataspace.getSimpleExtentNdims() != 0) {
throw std::runtime_error(LOCATION + "Expected " + dataset_name +
" to be a scalar dataset");
}
H5::DataType data_type = dataset.getDataType();
return h5_read_scalar_dataset<T>(dataset, data_type);
}
void Hdf5MasterFile::parse_acquisition_metadata(
const std::filesystem::path &fpath) {
try {
H5::H5File file(fpath, H5F_ACC_RDONLY);
// Attribute - version
double dVersion{0.0};
{
H5::Attribute attr = file.openAttribute("version");
H5::DataType attr_type = attr.getDataType();
attr.read(attr_type, &dVersion);
std::ostringstream oss;
oss << std::fixed << std::setprecision(1) << dVersion;
m_version = oss.str();
LOG(logDEBUG) << "Version: " << m_version;
}
// Scalar Dataset
H5::Exception::dontPrint();
// Detector Type
m_type = StringTo<DetectorType>(h5_get_scalar_dataset<std::string>(
file, std::string(metadata_group_name + "Detector Type")));
LOG(logDEBUG) << "Detector Type: " << ToString(m_type);
// Timing Mode
m_timing_mode = StringTo<TimingMode>(h5_get_scalar_dataset<std::string>(
file, std::string(metadata_group_name + "Timing Mode")));
LOG(logDEBUG) << "Timing Mode: " << ToString(m_timing_mode);
// Geometry
m_geometry.row = h5_get_scalar_dataset<int>(
file, std::string(metadata_group_name + "Geometry in y axis"));
m_geometry.col = h5_get_scalar_dataset<int>(
file, std::string(metadata_group_name + "Geometry in x axis"));
LOG(logDEBUG) << "Geometry: " << m_geometry.to_string();
// Image Size
m_image_size_in_bytes = h5_get_scalar_dataset<int>(
file, std::string(metadata_group_name + "Image Size"));
LOG(logDEBUG) << "Image size: " << m_image_size_in_bytes;
// Pixels y
m_pixels_y = h5_get_scalar_dataset<int>(
file,
std::string(metadata_group_name + "Number of pixels in y axis"));
LOG(logDEBUG) << "Pixels in y: " << m_pixels_y;
// Pixels x
m_pixels_x = h5_get_scalar_dataset<int>(
file,
std::string(metadata_group_name + "Number of pixels in x axis"));
LOG(logDEBUG) << "Pixels in x: " << m_pixels_x;
// Max Frames Per File
m_max_frames_per_file = h5_get_scalar_dataset<int>(
file, std::string(metadata_group_name + "Maximum frames per file"));
LOG(logDEBUG) << "Max frames per File: " << m_max_frames_per_file;
// Frame Discard Policy
m_frame_discard_policy =
StringTo<FrameDiscardPolicy>(h5_get_scalar_dataset<std::string>(
file,
std::string(metadata_group_name + "Frame Discard Policy")));
LOG(logDEBUG) << "Frame Discard Policy: "
<< ToString(m_frame_discard_policy);
// Frame Padding
m_frame_padding = h5_get_scalar_dataset<int>(
file, std::string(metadata_group_name + "Frame Padding"));
LOG(logDEBUG) << "Frame Padding: " << m_frame_padding;
// Scan Parameters
try {
std::string scan_parameters = h5_get_scalar_dataset<std::string>(
file, std::string(metadata_group_name + "Scan Parameters"));
m_scan_parameters = ScanParameters(scan_parameters);
if (dVersion < 6.61) {
m_scan_parameters
->increment_stop(); // adjust for endpoint being included
}
LOG(logDEBUG) << "Scan Parameters: " << ToString(m_scan_parameters);
} catch (H5::FileIException &e) {
// keep the optional empty
}
// Total Frames Expected
m_total_frames_expected = h5_get_scalar_dataset<size_t>(
file, std::string(metadata_group_name + "Total Frames"));
LOG(logDEBUG) << "Total Frames: " << m_total_frames_expected;
// Exptime
try {
m_exptime = StringTo<ns>(h5_get_scalar_dataset<std::string>(
file, std::string(metadata_group_name + "Exposure Time")));
LOG(logDEBUG) << "Exptime: " << ToString(m_exptime);
} catch (H5::FileIException &e) {
// keep the optional empty
}
// Period
try {
m_period = StringTo<ns>(h5_get_scalar_dataset<std::string>(
file, std::string(metadata_group_name + "Acquisition Period")));
LOG(logDEBUG) << "Period: " << ToString(m_period);
} catch (H5::FileIException &e) {
// keep the optional empty
}
// burst mode
try {
m_burst_mode =
StringTo<BurstMode>(h5_get_scalar_dataset<std::string>(
file, std::string(metadata_group_name + "Burst Mode")));
LOG(logDEBUG) << "Burst Mode: " << ToString(m_burst_mode);
} catch (H5::FileIException &e) {
// keep the optional empty
}
// Number of UDP Interfaces
// Not all detectors write the Number of UDP Interfaces but in case
try {
m_number_of_udp_interfaces = h5_get_scalar_dataset<int>(
file,
std::string(metadata_group_name + "Number of UDP Interfaces"));
LOG(logDEBUG) << "Number of UDP Interfaces: "
<< m_number_of_udp_interfaces;
} catch (H5::FileIException &e) {
// keep the optional empty
}
// Bit Depth
// Not all detectors write the bitdepth but in case
// its not there it is 16
try {
m_bitdepth = h5_get_scalar_dataset<int>(
file, std::string(metadata_group_name + "Dynamic Range"));
LOG(logDEBUG) << "Bit Depth: " << m_bitdepth;
} catch (H5::FileIException &e) {
m_bitdepth = 16;
}
// Ten Giga
try {
m_ten_giga = h5_get_scalar_dataset<bool>(
file, std::string(metadata_group_name + "Ten Giga Enable"));
LOG(logDEBUG) << "Ten Giga Enable: " << m_ten_giga;
} catch (H5::FileIException &e) {
// keep the optional empty
}
// Threshold Energy
try {
m_threshold_energy = h5_get_scalar_dataset<int>(
file, std::string(metadata_group_name + "Threshold Energy"));
LOG(logDEBUG) << "Threshold Energy: " << m_threshold_energy;
} catch (H5::FileIException &e) {
// keep the optional empty
}
// Threshold All Energy
try {
m_threshold_energy_all =
StringTo<std::vector<int>>(h5_get_scalar_dataset<std::string>(
file,
std::string(metadata_group_name + "Threshold Energies")));
LOG(logDEBUG) << "Threshold Energies: "
<< ToString(m_threshold_energy_all);
} catch (H5::FileIException &e) {
// keep the optional empty
}
// Subexptime
try {
m_subexptime = StringTo<ns>(h5_get_scalar_dataset<std::string>(
file, std::string(metadata_group_name + "Sub Exposure Time")));
LOG(logDEBUG) << "Subexptime: " << ToString(m_subexptime);
} catch (H5::FileIException &e) {
// keep the optional empty
}
// Subperiod
try {
m_subperiod = StringTo<ns>(h5_get_scalar_dataset<std::string>(
file, std::string(metadata_group_name + "Sub Period")));
LOG(logDEBUG) << "Subperiod: " << ToString(m_subperiod);
} catch (H5::FileIException &e) {
// keep the optional empty
}
// Quad
try {
m_quad = h5_get_scalar_dataset<bool>(
file, std::string(metadata_group_name + "Quad"));
LOG(logDEBUG) << "Quad: " << m_quad;
} catch (H5::FileIException &e) {
// keep the optional empty
}
// Number of Rows
// Not all detectors write the Number of rows but in case
try {
m_number_of_rows = h5_get_scalar_dataset<int>(
file, std::string(metadata_group_name + "Number of rows"));
LOG(logDEBUG) << "Number of rows: " << m_number_of_rows;
} catch (H5::FileIException &e) {
// keep the optional empty
}
// Rate Corrections
try {
m_rate_corrections = StringTo<std::vector<size_t>>(
h5_get_scalar_dataset<std::string>(
file,
std::string(metadata_group_name + "Rate Corrections")));
LOG(logDEBUG) << "Rate Corrections: "
<< ToString(m_rate_corrections);
} catch (H5::FileIException &e) {
// keep the optional empty
}
// ADC Mask
try {
m_adc_mask = h5_get_scalar_dataset<uint32_t>(
file, std::string(metadata_group_name + "ADC Mask"));
LOG(logDEBUG) << "ADC Mask: " << m_adc_mask;
} catch (H5::FileIException &e) {
// keep the optional empty
}
// Analog Flag
// ----------------------------------------------------------------
// Special treatment of analog flag because of Moench03
try {
m_analog_flag = h5_get_scalar_dataset<uint8_t>(
file, std::string(metadata_group_name + "Analog Flag"));
LOG(logDEBUG) << "Analog Flag: " << m_analog_flag;
} catch (H5::FileIException &e) {
// if it doesn't work still set it to one
// to try to decode analog samples (Old Moench03)
m_analog_flag = 1;
}
// Analog Samples
try {
if (m_analog_flag) {
m_analog_samples = h5_get_scalar_dataset<int>(
file, std::string(metadata_group_name + "Analog Samples"));
LOG(logDEBUG) << "Analog Samples: " << m_analog_samples;
}
} catch (H5::FileIException &e) {
// keep the optional empty
// and set analog flag to 0
m_analog_flag = false;
}
//-----------------------------------------------------------------
// Digital Flag, Digital Samples
try {
m_digital_flag = h5_get_scalar_dataset<bool>(
file, std::string(metadata_group_name + "Digital Flag"));
LOG(logDEBUG) << "Digital Flag: " << m_digital_flag;
if (m_digital_flag) {
m_digital_samples = h5_get_scalar_dataset<int>(
file, std::string(metadata_group_name + "Digital Samples"));
}
LOG(logDEBUG) << "Digital Samples: " << m_digital_samples;
} catch (H5::FileIException &e) {
m_digital_flag = false;
}
// Dbit Offset
try {
m_dbit_offset = h5_get_scalar_dataset<int>(
file, std::string(metadata_group_name + "Dbit Offset"));
LOG(logDEBUG) << "Dbit Offset: " << m_dbit_offset;
} catch (H5::FileIException &e) {
// keep the optional empty
}
// Dbit List
try {
m_dbit_list = h5_get_scalar_dataset<size_t>(
file, std::string(metadata_group_name + "Dbit Bitset List"));
LOG(logDEBUG) << "Dbit list: " << m_dbit_list;
} catch (H5::FileIException &e) {
// keep the optional empty
}
// Transceiver Mask
try {
m_transceiver_mask = h5_get_scalar_dataset<int>(
file, std::string(metadata_group_name + "Transceiver Mask"));
LOG(logDEBUG) << "Transceiver Mask: " << m_transceiver_mask;
} catch (H5::FileIException &e) {
// keep the optional empty
}
// Transceiver Flag, Transceiver Samples
try {
m_transceiver_flag = h5_get_scalar_dataset<bool>(
file, std::string(metadata_group_name + "Transceiver Flag"));
LOG(logDEBUG) << "Transceiver Flag: " << m_transceiver_flag;
if (m_transceiver_flag) {
m_transceiver_samples = h5_get_scalar_dataset<int>(
file,
std::string(metadata_group_name + "Transceiver Samples"));
LOG(logDEBUG)
<< "Transceiver Samples: " << m_transceiver_samples;
}
} catch (H5::FileIException &e) {
m_transceiver_flag = false;
}
// Rx ROI
try {
ROI tmp_roi;
tmp_roi.xmin = h5_get_scalar_dataset<int>(
file, std::string(metadata_group_name + "receiver roi xmin"));
tmp_roi.xmax = h5_get_scalar_dataset<int>(
file, std::string(metadata_group_name + "receiver roi xmax"));
tmp_roi.ymin = h5_get_scalar_dataset<int>(
file, std::string(metadata_group_name + "receiver roi ymin"));
tmp_roi.ymax = h5_get_scalar_dataset<int>(
file, std::string(metadata_group_name + "receiver roi ymax"));
// if any of the values are set update the roi
if (tmp_roi.xmin != -1 || tmp_roi.xmax != -1 ||
tmp_roi.ymin != -1 || tmp_roi.ymax != -1) {
// why?? TODO
//if (dVersion < 6.6) {
tmp_roi.xmax++;
tmp_roi.ymax++;
//}
m_roi = tmp_roi;
}
LOG(logDEBUG) << "ROI: " << m_roi;
} catch (H5::FileIException &e) {
// keep the optional empty
}
// Update detector type for Moench
// TODO! How does this work with old .h5 master files?
#ifdef AARE_VERBOSE
fmt::print("Detecting Moench03: m_pixels_y: {}, "
"m_analog_samples: {}\n",
m_pixels_y, m_analog_samples.value_or(0));
#endif
if (m_type == DetectorType::Moench && !m_analog_samples &&
m_pixels_y == 400) {
m_type = DetectorType::Moench03;
} else if (m_type == DetectorType::Moench && m_pixels_y == 400 &&
m_analog_samples == 5000) {
m_type = DetectorType::Moench03_old;
}
// Counter Mask
try {
m_counter_mask = h5_get_scalar_dataset<int>(
file, std::string(metadata_group_name + "Counter Mask"));
LOG(logDEBUG) << "Counter Mask: " << m_counter_mask;
} catch (H5::FileIException &e) {
// keep the optional empty
}
// Exposure Time Array
try {
m_exptime_array =
StringTo<std::vector<ns>>(h5_get_scalar_dataset<std::string>(
file, std::string(metadata_group_name + "Exposure Times")));
LOG(logDEBUG) << "Exposure Times: " << ToString(m_exptime_array);
} catch (H5::FileIException &e) {
// keep the optional empty
}
// Gate Delay Array
try {
m_gate_delay_array =
StringTo<std::vector<ns>>(h5_get_scalar_dataset<std::string>(
file, std::string(metadata_group_name + "Gate Delays")));
LOG(logDEBUG) << "Gate Delays: " << ToString(m_gate_delay_array);
} catch (H5::FileIException &e) {
// keep the optional empty
}
// Gates
try {
m_gates = h5_get_scalar_dataset<int>(
file, std::string(metadata_group_name + "Gates"));
LOG(logDEBUG) << "Gates: " << m_gates;
} catch (H5::FileIException &e) {
// keep the optional empty
}
// Additional Json Header
try {
m_additional_json_header =
StringTo<std::map<std::string, std::string>>(
h5_get_scalar_dataset<std::string>(
file, std::string(metadata_group_name +
"Additional JSON Header")));
LOG(logDEBUG) << "Additional JSON Header: "
<< ToString(m_additional_json_header);
} catch (H5::FileIException &e) {
// keep the optional empty
}
// Frames in File
m_frames_in_file = h5_get_scalar_dataset<size_t>(
file, std::string(metadata_group_name + "Frames in File"));
LOG(logDEBUG) << "Frames in File: " << m_frames_in_file;
H5Eset_auto(H5E_DEFAULT, reinterpret_cast<H5E_auto2_t>(H5Eprint2),
stderr);
} catch (const H5::Exception &e) {
fmt::print("Exception type: {}\n", typeid(e).name());
e.printErrorStack();
throw std::runtime_error(LOCATION + "\nCould not parse master file");
}
}
} // namespace aare

View File

@ -1,168 +0,0 @@
#include "aare/Hdf5MasterFile.hpp"
#include "aare/to_string.hpp"
#include "test_config.hpp"
#include <catch2/catch_test_macros.hpp>
using namespace aare;
TEST_CASE("Parse a multi module jungfrau master file in .h5 format", "[.integration][.hdf5]") {
auto fpath = test_data_path() / "hdf5" / "virtual" / "jungfrau" /
"two_modules_master_0.h5";
REQUIRE(std::filesystem::exists(fpath));
Hdf5MasterFile f(fpath);
REQUIRE(f.version() == "6.6");
// "Timestamp": "Tue Feb 20 08:28:24 2024",
REQUIRE(f.detector_type() == DetectorType::Jungfrau);
REQUIRE(f.timing_mode() == TimingMode::Auto);
REQUIRE(f.geometry().col == 1);
REQUIRE(f.geometry().row == 2);
REQUIRE(f.image_size_in_bytes() == 1048576);
REQUIRE(f.pixels_x() == 1024);
REQUIRE(f.pixels_y() == 512);
REQUIRE(f.max_frames_per_file() == 10000);
REQUIRE(f.frame_discard_policy() == FrameDiscardPolicy::NoDiscard);
REQUIRE(f.frame_padding() == 1);
REQUIRE(f.scan_parameters()->enabled() == false);
REQUIRE(f.total_frames_expected() == 5);
REQUIRE(f.exptime() == std::chrono::microseconds(10));
REQUIRE(f.period() == std::chrono::milliseconds(2));
REQUIRE_FALSE(f.burst_mode().has_value());
REQUIRE(f.number_of_udp_interfaces() == 1);
// Jungfrau doesn't write but it is 16
REQUIRE(f.bitdepth() == 16);
REQUIRE_FALSE(f.ten_giga().has_value());
REQUIRE_FALSE(f.threshold_energy().has_value());
REQUIRE_FALSE(f.threshold_energy_all().has_value());
REQUIRE_FALSE(f.subexptime().has_value());
REQUIRE_FALSE(f.subperiod().has_value());
REQUIRE_FALSE(f.quad().has_value());
REQUIRE(f.number_of_rows() == 512);
REQUIRE_FALSE(f.rate_corrections().has_value());
REQUIRE_FALSE(f.adc_mask().has_value());
REQUIRE_FALSE(f.analog_flag());
REQUIRE_FALSE(f.analog_samples().has_value());
REQUIRE_FALSE(f.digital_flag());
REQUIRE_FALSE(f.digital_samples().has_value());
REQUIRE_FALSE(f.dbit_offset().has_value());
REQUIRE_FALSE(f.dbit_list().has_value());
REQUIRE_FALSE(f.transceiver_mask().has_value());
REQUIRE_FALSE(f.transceiver_flag());
REQUIRE_FALSE(f.transceiver_samples().has_value());
REQUIRE_FALSE(f.roi().has_value());
REQUIRE_FALSE(f.counter_mask().has_value());
REQUIRE_FALSE(f.exptime_array().has_value());
REQUIRE_FALSE(f.gate_delay_array().has_value());
REQUIRE_FALSE(f.gates().has_value());
REQUIRE_FALSE(f.additional_json_header().has_value());
REQUIRE(f.frames_in_file() == 5);
REQUIRE(f.n_modules() == 2);
}
TEST_CASE("Parse a single module jungfrau master file in .h5 format", "[.integration][.hdf5]") {
auto fpath = test_data_path() / "hdf5" / "virtual" / "jungfrau" /
"single_module_master_2.h5";
REQUIRE(std::filesystem::exists(fpath));
Hdf5MasterFile f(fpath);
REQUIRE(f.version() == "6.6");
// "Timestamp": "Tue Feb 20 08:28:24 2024",
REQUIRE(f.detector_type() == DetectorType::Jungfrau);
REQUIRE(f.timing_mode() == TimingMode::Auto);
REQUIRE(f.geometry().col == 1);
REQUIRE(f.geometry().row == 1);
REQUIRE(f.image_size_in_bytes() == 1048576);
REQUIRE(f.pixels_x() == 1024);
REQUIRE(f.pixels_y() == 512);
REQUIRE(f.max_frames_per_file() == 10000);
REQUIRE(f.frame_discard_policy() == FrameDiscardPolicy::NoDiscard);
REQUIRE(f.frame_padding() == 1);
REQUIRE(f.scan_parameters()->enabled() == false);
REQUIRE(f.total_frames_expected() == 5);
REQUIRE(f.exptime() == std::chrono::microseconds(10));
REQUIRE(f.period() == std::chrono::milliseconds(2));
REQUIRE_FALSE(f.burst_mode().has_value());
REQUIRE(f.number_of_udp_interfaces() == 1);
// Jungfrau doesn't write but it is 16
REQUIRE(f.bitdepth() == 16);
REQUIRE_FALSE(f.ten_giga().has_value());
REQUIRE_FALSE(f.threshold_energy().has_value());
REQUIRE_FALSE(f.threshold_energy_all().has_value());
REQUIRE_FALSE(f.subexptime().has_value());
REQUIRE_FALSE(f.subperiod().has_value());
REQUIRE_FALSE(f.quad().has_value());
REQUIRE(f.number_of_rows() == 512);
REQUIRE_FALSE(f.rate_corrections().has_value());
REQUIRE_FALSE(f.adc_mask().has_value());
REQUIRE_FALSE(f.analog_flag());
REQUIRE_FALSE(f.analog_samples().has_value());
REQUIRE_FALSE(f.digital_flag());
REQUIRE_FALSE(f.digital_samples().has_value());
REQUIRE_FALSE(f.dbit_offset().has_value());
REQUIRE_FALSE(f.dbit_list().has_value());
REQUIRE_FALSE(f.transceiver_mask().has_value());
REQUIRE_FALSE(f.transceiver_flag());
REQUIRE_FALSE(f.transceiver_samples().has_value());
REQUIRE_FALSE(f.roi().has_value());
REQUIRE_FALSE(f.counter_mask().has_value());
REQUIRE_FALSE(f.exptime_array().has_value());
REQUIRE_FALSE(f.gate_delay_array().has_value());
REQUIRE_FALSE(f.gates().has_value());
REQUIRE_FALSE(f.additional_json_header().has_value());
REQUIRE(f.frames_in_file() == 5);
REQUIRE(f.n_modules() == 1);
}
TEST_CASE("Parse a mythen3 master file in .h5 format", "[.integration][.hdf5]") {
auto fpath = test_data_path() / "hdf5" / "virtual" / "mythen3" /
"one_module_master_0.h5";
REQUIRE(std::filesystem::exists(fpath));
Hdf5MasterFile f(fpath);
REQUIRE(f.version() == "6.7");
// "Timestamp": "Tue Feb 20 08:28:24 2024",
REQUIRE(f.detector_type() == DetectorType::Mythen3);
REQUIRE(f.timing_mode() == TimingMode::Auto);
REQUIRE(f.geometry().col == 1);
REQUIRE(f.geometry().row == 1);
REQUIRE(f.image_size_in_bytes() == 15360);
REQUIRE(f.pixels_x() == 3840);
REQUIRE(f.pixels_y() == 1);
REQUIRE(f.max_frames_per_file() == 10000);
REQUIRE(f.frame_discard_policy() == FrameDiscardPolicy::NoDiscard);
REQUIRE(f.frame_padding() == 1);
REQUIRE(f.scan_parameters()->enabled() == false);
REQUIRE(f.total_frames_expected() == 1);
REQUIRE_FALSE(f.exptime().has_value());
REQUIRE(f.period() == std::chrono::nanoseconds(0));
REQUIRE_FALSE(f.burst_mode().has_value());
REQUIRE_FALSE(f.number_of_udp_interfaces().has_value());
REQUIRE(f.bitdepth() == 32);
REQUIRE(f.ten_giga() == 1);
REQUIRE_FALSE(f.threshold_energy().has_value());
REQUIRE(ToString(f.threshold_energy_all()) == "[-1, -1, -1]");
REQUIRE_FALSE(f.subexptime().has_value());
REQUIRE_FALSE(f.subperiod().has_value());
REQUIRE_FALSE(f.quad().has_value());
REQUIRE_FALSE(f.number_of_rows().has_value());
REQUIRE_FALSE(f.rate_corrections().has_value());
REQUIRE_FALSE(f.adc_mask().has_value());
REQUIRE_FALSE(f.analog_flag());
REQUIRE_FALSE(f.analog_samples().has_value());
REQUIRE_FALSE(f.digital_flag());
REQUIRE_FALSE(f.digital_samples().has_value());
REQUIRE_FALSE(f.dbit_offset().has_value());
REQUIRE_FALSE(f.dbit_list().has_value());
REQUIRE_FALSE(f.transceiver_mask().has_value());
REQUIRE_FALSE(f.transceiver_flag());
REQUIRE_FALSE(f.transceiver_samples().has_value());
REQUIRE_FALSE(f.roi().has_value());
REQUIRE(f.counter_mask() == 0x7);
REQUIRE(ToString(f.exptime_array()) == "[0.1s, 0.1s, 0.1s]");
REQUIRE(ToString(f.gate_delay_array()) == "[0ns, 0ns, 0ns]");
REQUIRE(f.gates() == 1);
REQUIRE_FALSE(f.additional_json_header().has_value());
REQUIRE(f.frames_in_file() == 1);
REQUIRE(f.n_modules() == 1);
}

View File

@ -1,5 +1,4 @@
#include "aare/RawMasterFile.hpp"
#include "aare/to_string.hpp"
#include <sstream>
namespace aare {
@ -62,6 +61,32 @@ const std::string &RawFileNameComponents::base_name() const {
const std::string &RawFileNameComponents::ext() const { return m_ext; }
int RawFileNameComponents::file_index() const { return m_file_index; }
// "[enabled\ndac dac 4\nstart 500\nstop 2200\nstep 5\nsettleTime 100us\n]"
ScanParameters::ScanParameters(const std::string &par) {
std::istringstream iss(par.substr(1, par.size() - 2));
std::string line;
while (std::getline(iss, line)) {
if (line == "enabled") {
m_enabled = true;
} else if (line.find("dac") != std::string::npos) {
m_dac = line.substr(4);
} else if (line.find("start") != std::string::npos) {
m_start = std::stoi(line.substr(6));
} else if (line.find("stop") != std::string::npos) {
m_stop = std::stoi(line.substr(5));
} else if (line.find("step") != std::string::npos) {
m_step = std::stoi(line.substr(5));
}
}
}
int ScanParameters::start() const { return m_start; }
int ScanParameters::stop() const { return m_stop; }
void ScanParameters::increment_stop() { m_stop += 1; }
int ScanParameters::step() const { return m_step; }
const std::string &ScanParameters::dac() const { return m_dac; }
bool ScanParameters::enabled() const { return m_enabled; }
RawMasterFile::RawMasterFile(const std::filesystem::path &fpath)
: m_fnc(fpath) {
if (!std::filesystem::exists(fpath)) {

View File

@ -46,6 +46,25 @@ TEST_CASE("Master file name does not fit pattern") {
REQUIRE_THROWS(RawFileNameComponents("test_master_1.txt"));
}
TEST_CASE("Parse scan parameters") {
ScanParameters s("[enabled\ndac dac 4\nstart 500\nstop 2200\nstep "
"5\nsettleTime 100us\n]");
REQUIRE(s.enabled());
REQUIRE(s.dac() == "dac 4");
REQUIRE(s.start() == 500);
REQUIRE(s.stop() == 2200);
REQUIRE(s.step() == 5);
}
TEST_CASE("A disabled scan") {
ScanParameters s("[disabled]");
REQUIRE_FALSE(s.enabled());
REQUIRE(s.dac() == "");
REQUIRE(s.start() == 0);
REQUIRE(s.stop() == 0);
REQUIRE(s.step() == 0);
}
TEST_CASE("Parse a master file in .json format", "[.integration]") {
auto fpath =
test_data_path() / "jungfrau" / "jungfrau_single_master_0.json";

View File

@ -1,4 +1,6 @@
#include "aare/defs.hpp"
#include <stdexcept>
#include <string>
#include <fmt/core.h>
namespace aare {
@ -8,4 +10,109 @@ void assert_failed(const std::string &msg) {
exit(1);
}
/**
* @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::Generic:
return "Generic";
case DetectorType::Eiger:
return "Eiger";
case DetectorType::Gotthard:
return "Gotthard";
case DetectorType::Jungfrau:
return "Jungfrau";
case DetectorType::ChipTestBoard:
return "ChipTestBoard";
case DetectorType::Moench:
return "Moench";
case DetectorType::Mythen3:
return "Mythen3";
case DetectorType::Gotthard2:
return "Gotthard2";
case DetectorType::Xilinx_ChipTestBoard:
return "Xilinx_ChipTestBoard";
// Custom ones
case DetectorType::Moench03:
return "Moench03";
case DetectorType::Moench03_old:
return "Moench03_old";
case DetectorType::Unknown:
return "Unknown";
// no default case to trigger compiler warning if not all
// enum values are handled
}
throw std::runtime_error("Could not decode detector to string");
}
/**
* @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 == "Generic")
return DetectorType::Generic;
if (arg == "Eiger")
return DetectorType::Eiger;
if (arg == "Gotthard")
return DetectorType::Gotthard;
if (arg == "Jungfrau")
return DetectorType::Jungfrau;
if (arg == "ChipTestBoard")
return DetectorType::ChipTestBoard;
if (arg == "Moench")
return DetectorType::Moench;
if (arg == "Mythen3")
return DetectorType::Mythen3;
if (arg == "Gotthard2")
return DetectorType::Gotthard2;
if (arg == "Xilinx_ChipTestBoard")
return DetectorType::Xilinx_ChipTestBoard;
// Custom ones
if (arg == "Moench03")
return DetectorType::Moench03;
if (arg == "Moench03_old")
return DetectorType::Moench03_old;
if (arg == "Unknown")
return DetectorType::Unknown;
throw std::runtime_error("Could not decode detector 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 <> FrameDiscardPolicy StringTo(const std::string &arg) {
if (arg == "nodiscard")
return FrameDiscardPolicy::NoDiscard;
if (arg == "discard")
return FrameDiscardPolicy::Discard;
if (arg == "discardpartial")
return FrameDiscardPolicy::DiscardPartial;
throw std::runtime_error("Could not decode frame discard policy from: \"" +
arg + "\"");
}
// template <> TimingMode StringTo<TimingMode>(std::string mode);
} // namespace aare

View File

@ -1,6 +1,54 @@
#include "aare/defs.hpp"
#include <catch2/catch_test_macros.hpp>
#include <string>
using aare::StringTo;
using aare::ToString;
TEST_CASE("Enum to string conversion") {
// TODO! 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::Generic) == "Generic");
REQUIRE(ToString(aare::DetectorType::Eiger) == "Eiger");
REQUIRE(ToString(aare::DetectorType::Gotthard) == "Gotthard");
REQUIRE(ToString(aare::DetectorType::Jungfrau) == "Jungfrau");
REQUIRE(ToString(aare::DetectorType::ChipTestBoard) == "ChipTestBoard");
REQUIRE(ToString(aare::DetectorType::Moench) == "Moench");
REQUIRE(ToString(aare::DetectorType::Mythen3) == "Mythen3");
REQUIRE(ToString(aare::DetectorType::Gotthard2) == "Gotthard2");
REQUIRE(ToString(aare::DetectorType::Xilinx_ChipTestBoard) ==
"Xilinx_ChipTestBoard");
REQUIRE(ToString(aare::DetectorType::Moench03) == "Moench03");
REQUIRE(ToString(aare::DetectorType::Moench03_old) == "Moench03_old");
REQUIRE(ToString(aare::DetectorType::Unknown) == "Unknown");
}
TEST_CASE("String to enum") {
REQUIRE(StringTo<aare::DetectorType>("Generic") ==
aare::DetectorType::Generic);
REQUIRE(StringTo<aare::DetectorType>("Eiger") == aare::DetectorType::Eiger);
REQUIRE(StringTo<aare::DetectorType>("Gotthard") ==
aare::DetectorType::Gotthard);
REQUIRE(StringTo<aare::DetectorType>("Jungfrau") ==
aare::DetectorType::Jungfrau);
REQUIRE(StringTo<aare::DetectorType>("ChipTestBoard") ==
aare::DetectorType::ChipTestBoard);
REQUIRE(StringTo<aare::DetectorType>("Moench") ==
aare::DetectorType::Moench);
REQUIRE(StringTo<aare::DetectorType>("Mythen3") ==
aare::DetectorType::Mythen3);
REQUIRE(StringTo<aare::DetectorType>("Gotthard2") ==
aare::DetectorType::Gotthard2);
REQUIRE(StringTo<aare::DetectorType>("Xilinx_ChipTestBoard") ==
aare::DetectorType::Xilinx_ChipTestBoard);
REQUIRE(StringTo<aare::DetectorType>("Moench03") ==
aare::DetectorType::Moench03);
REQUIRE(StringTo<aare::DetectorType>("Moench03_old") ==
aare::DetectorType::Moench03_old);
REQUIRE(StringTo<aare::DetectorType>("Unknown") ==
aare::DetectorType::Unknown);
}
TEST_CASE("Enum values") {
// Since some of the enums are written to file we need to make sure

View File

@ -1,26 +0,0 @@
#include "aare/scan_parameters.hpp"
#include <catch2/catch_test_macros.hpp>
using namespace aare;
// TODO: Move these to to_string.test.cpp once ToSTring is implemented
TEST_CASE("Parse scan parameters") {
ScanParameters s("[enabled\ndac dac 4\nstart 500\nstop 2200\nstep "
"5\nsettleTime 100us\n]");
REQUIRE(s.enabled());
REQUIRE(s.dac() == "dac 4");
REQUIRE(s.start() == 500);
REQUIRE(s.stop() == 2200);
REQUIRE(s.step() == 5);
}
TEST_CASE("A disabled scan") {
ScanParameters s("[disabled]");
REQUIRE_FALSE(s.enabled());
REQUIRE(s.dac() == "");
REQUIRE(s.start() == 0);
REQUIRE(s.stop() == 0);
REQUIRE(s.step() == 0);
}

View File

@ -1,30 +0,0 @@
#include "aare/string_utils.hpp"
#include <algorithm>
namespace aare {
std::string RemoveUnit(std::string &str) {
auto it = str.begin();
while (it != str.end()) {
if (std::isalpha(*it))
break;
++it;
}
auto pos = it - str.begin();
auto unit = str.substr(pos);
str.erase(it, end(str));
return unit;
}
void TrimWhiteSpaces(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char c) {
return !std::isspace(c);
}));
s.erase(std::find_if(s.rbegin(), s.rend(),
[](unsigned char c) { return !std::isspace(c); })
.base(),
s.end());
}
} // namespace aare

View File

@ -1,226 +0,0 @@
#include "aare/to_string.hpp"
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::Generic:
return "Generic";
case DetectorType::Eiger:
return "Eiger";
case DetectorType::Gotthard:
return "Gotthard";
case DetectorType::Jungfrau:
return "Jungfrau";
case DetectorType::ChipTestBoard:
return "ChipTestBoard";
case DetectorType::Moench:
return "Moench";
case DetectorType::Mythen3:
return "Mythen3";
case DetectorType::Gotthard2:
return "Gotthard2";
case DetectorType::Xilinx_ChipTestBoard:
return "Xilinx_ChipTestBoard";
// Custom ones
case DetectorType::Moench03:
return "Moench03";
case DetectorType::Moench03_old:
return "Moench03_old";
case DetectorType::Unknown:
return "Unknown";
// no default case to trigger compiler warning if not all
// enum values are handled
}
throw std::runtime_error("Could not decode detector to string");
}
/**
* @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 == "Generic")
return DetectorType::Generic;
if (arg == "Eiger")
return DetectorType::Eiger;
if (arg == "Gotthard")
return DetectorType::Gotthard;
if (arg == "Jungfrau")
return DetectorType::Jungfrau;
if (arg == "ChipTestBoard")
return DetectorType::ChipTestBoard;
if (arg == "Moench")
return DetectorType::Moench;
if (arg == "Mythen3")
return DetectorType::Mythen3;
if (arg == "Gotthard2")
return DetectorType::Gotthard2;
if (arg == "Xilinx_ChipTestBoard")
return DetectorType::Xilinx_ChipTestBoard;
// Custom ones
if (arg == "Moench03")
return DetectorType::Moench03;
if (arg == "Moench03_old")
return DetectorType::Moench03_old;
if (arg == "Unknown")
return DetectorType::Unknown;
throw std::runtime_error("Could not decode detector from: \"" + arg + "\"");
}
/**
* @brief Convert a TimingMode to a string
* @param type TimingMode
* @return string representation of the TimingMode
*/
template <> std::string ToString(TimingMode arg) {
switch (arg) {
case TimingMode::Auto:
return "Auto";
case TimingMode::Trigger:
return "Trigger";
// no default case to trigger compiler warning if not all
// enum values are handled
}
throw std::runtime_error("Could not decode timing mode to string");
}
/**
* @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 +
"\"");
}
/**
* @brief Convert a FrameDiscardPolicy to a string
* @param type FrameDiscardPolicy
* @return string representation of the FrameDiscardPolicy
*/
template <> std::string ToString(FrameDiscardPolicy arg) {
switch (arg) {
case FrameDiscardPolicy::NoDiscard:
return "nodiscard";
case FrameDiscardPolicy::Discard:
return "discard";
case FrameDiscardPolicy::DiscardPartial:
return "discardpartial";
// no default case to trigger compiler warning if not all
// enum values are handled
}
throw std::runtime_error("Could not decode frame discard policy to string");
}
template <> FrameDiscardPolicy StringTo(const std::string &arg) {
if (arg == "nodiscard")
return FrameDiscardPolicy::NoDiscard;
if (arg == "discard")
return FrameDiscardPolicy::Discard;
if (arg == "discardpartial")
return FrameDiscardPolicy::DiscardPartial;
throw std::runtime_error("Could not decode frame discard policy from: \"" +
arg + "\"");
}
/**
* @brief Convert a BurstMode to a string
* @param type BurstMode
* @return string representation of the BurstMode
*/
template <> std::string ToString(BurstMode arg) {
switch (arg) {
case BurstMode::Burst_Interal:
return "burst_internal";
case BurstMode::Burst_External:
return "burst_external";
case BurstMode::Continuous_Internal:
return "continuous_internal";
case BurstMode::Continuous_External:
return "continuous_external";
}
throw std::runtime_error("Could not decode burst mode to string");
}
template <> BurstMode StringTo(const std::string &arg) {
if (arg == "burst_internal")
return BurstMode::Burst_Interal;
if (arg == "burst_external")
return BurstMode::Burst_External;
if (arg == "continuous_internal")
return BurstMode::Continuous_Internal;
if (arg == "continuous_external")
return BurstMode::Continuous_External;
throw std::runtime_error("Could not decode burst mode from: \"" + arg +
"\"");
}
/**
* @brief Convert a ScanParameters to a string
* @param type ScanParameters
* @return string representation of the ScanParameters
*/
template <> std::string ToString(ScanParameters arg) {
std::ostringstream oss;
oss << '[';
if (arg.enabled()) {
oss << "enabled" << std::endl
<< "dac " << arg.dac() << std::endl
<< "start " << arg.start() << std::endl
<< "stop " << arg.stop() << std::endl
<< "step " << arg.step()
<< std::endl
//<< "settleTime "
// << ToString(std::chrono::nanoseconds{arg.dacSettleTime_ns})
<< std::endl;
} else {
oss << "disabled";
}
oss << ']';
return oss.str();
}
std::ostream &operator<<(std::ostream &os, const ScanParameters &r) {
return os << ToString(r);
}
/**
* @brief Convert a ROI to a string
* @param type ROI
* @return string representation of the ROI
*/
template <> std::string ToString(ROI arg) {
std::ostringstream oss;
oss << '[' << arg.xmin << ", " << arg.xmax;
if (arg.ymin != -1 || arg.ymax != -1) {
oss << ", " << arg.ymin << ", " << arg.ymax;
}
oss << ']';
return oss.str();
}
std::ostream &operator<<(std::ostream &os, const ROI &roi) {
return os << ToString(roi);
}
} // namespace aare

View File

@ -1,224 +0,0 @@
#include "aare/to_string.hpp"
#include <catch2/catch_test_macros.hpp>
using aare::StringTo;
using aare::ToString;
TEST_CASE("Detector Type to string conversion") {
// TODO! 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::Generic) == "Generic");
REQUIRE(ToString(aare::DetectorType::Eiger) == "Eiger");
REQUIRE(ToString(aare::DetectorType::Gotthard) == "Gotthard");
REQUIRE(ToString(aare::DetectorType::Jungfrau) == "Jungfrau");
REQUIRE(ToString(aare::DetectorType::ChipTestBoard) == "ChipTestBoard");
REQUIRE(ToString(aare::DetectorType::Moench) == "Moench");
REQUIRE(ToString(aare::DetectorType::Mythen3) == "Mythen3");
REQUIRE(ToString(aare::DetectorType::Gotthard2) == "Gotthard2");
REQUIRE(ToString(aare::DetectorType::Xilinx_ChipTestBoard) ==
"Xilinx_ChipTestBoard");
REQUIRE(ToString(aare::DetectorType::Moench03) == "Moench03");
REQUIRE(ToString(aare::DetectorType::Moench03_old) == "Moench03_old");
REQUIRE(ToString(aare::DetectorType::Unknown) == "Unknown");
}
TEST_CASE("String to Detector Type") {
REQUIRE(StringTo<aare::DetectorType>("Generic") ==
aare::DetectorType::Generic);
REQUIRE(StringTo<aare::DetectorType>("Eiger") == aare::DetectorType::Eiger);
REQUIRE(StringTo<aare::DetectorType>("Gotthard") ==
aare::DetectorType::Gotthard);
REQUIRE(StringTo<aare::DetectorType>("Jungfrau") ==
aare::DetectorType::Jungfrau);
REQUIRE(StringTo<aare::DetectorType>("ChipTestBoard") ==
aare::DetectorType::ChipTestBoard);
REQUIRE(StringTo<aare::DetectorType>("Moench") ==
aare::DetectorType::Moench);
REQUIRE(StringTo<aare::DetectorType>("Mythen3") ==
aare::DetectorType::Mythen3);
REQUIRE(StringTo<aare::DetectorType>("Gotthard2") ==
aare::DetectorType::Gotthard2);
REQUIRE(StringTo<aare::DetectorType>("Xilinx_ChipTestBoard") ==
aare::DetectorType::Xilinx_ChipTestBoard);
REQUIRE(StringTo<aare::DetectorType>("Moench03") ==
aare::DetectorType::Moench03);
REQUIRE(StringTo<aare::DetectorType>("Moench03_old") ==
aare::DetectorType::Moench03_old);
REQUIRE(StringTo<aare::DetectorType>("Unknown") ==
aare::DetectorType::Unknown);
}
TEST_CASE("conversion from duration to string") {
using ns = std::chrono::nanoseconds;
using us = std::chrono::microseconds;
using ms = std::chrono::milliseconds;
using s = std::chrono::seconds;
REQUIRE(ToString(ns(150)) == "150ns");
REQUIRE(ToString(ms(783)) == "0.783s");
REQUIRE(ToString(ms(783), "ms") == "783ms");
REQUIRE(ToString(us(0)) == "0ns"); // Defaults to the lowest unit
REQUIRE(ToString(us(0), "s") == "0s");
REQUIRE(ToString(s(-1)) == "-1s");
REQUIRE(ToString(us(-100)) == "-100us");
}
TEST_CASE("Convert vector of time") {
using ns = std::chrono::nanoseconds;
using us = std::chrono::microseconds;
using ms = std::chrono::milliseconds;
using s = std::chrono::seconds;
std::vector<ns> vec{ns(150), us(10), ns(600)};
REQUIRE(ToString(vec) == "[150ns, 10us, 600ns]");
vec[0] = ms(150);
vec[1] = s(10);
REQUIRE(ToString(vec) == "[0.15s, 10s, 600ns]");
// REQUIRE(ToString(vec, "ns") == "[150ns, 10000ns, 600ns]");
}
TEST_CASE("string to std::chrono::duration") {
using ns = std::chrono::nanoseconds;
using us = std::chrono::microseconds;
using ms = std::chrono::milliseconds;
using s = std::chrono::seconds;
REQUIRE(StringTo<ns>("150", "ns") == ns(150));
REQUIRE(StringTo<ns>("150us") == us(150));
REQUIRE(StringTo<ns>("150ms") == ms(150));
REQUIRE(StringTo<s>("3 s") == s(3));
REQUIRE_THROWS(StringTo<ns>("5xs"));
REQUIRE_THROWS(StringTo<ns>("asvn"));
}
TEST_CASE("Vector of int") {
std::vector<int> vec;
REQUIRE(ToString(vec) == "[]");
vec.push_back(1);
REQUIRE(ToString(vec) == "[1]");
vec.push_back(172);
REQUIRE(ToString(vec) == "[1, 172]");
vec.push_back(5000);
REQUIRE(ToString(vec) == "[1, 172, 5000]");
}
TEST_CASE("Vector of double") {
std::vector<double> vec;
REQUIRE(ToString(vec) == "[]");
vec.push_back(1.3);
REQUIRE(ToString(vec) == "[1.3]");
// vec.push_back(5669.325);
// REQUIRE(ToString(vec) == "[1.3, 5669.325]");
// vec.push_back(-5669.325005);
// REQUIRE(ToString(vec) == "[1.3, 5669.325, -5669.325005]");
}
TEST_CASE("String to string") {
std::string k = "hej";
REQUIRE(ToString(k) == "hej");
}
TEST_CASE("vector of strings") {
std::vector<std::string> vec{"5", "s"};
REQUIRE(ToString(vec) == "[5, s]");
std::vector<std::string> vec2{"some", "strange", "words", "75"};
REQUIRE(ToString(vec2) == "[some, strange, words, 75]");
}
TEST_CASE("uint32 from string") {
REQUIRE(StringTo<uint32_t>("0") == 0);
REQUIRE(StringTo<uint32_t>("5") == 5u);
REQUIRE(StringTo<uint32_t>("16") == 16u);
REQUIRE(StringTo<uint32_t>("20") == 20u);
REQUIRE(StringTo<uint32_t>("0x14") == 20u);
REQUIRE(StringTo<uint32_t>("0x15") == 21u);
REQUIRE(StringTo<uint32_t>("0x15") == 0x15);
REQUIRE(StringTo<uint32_t>("0xffffff") == 0xffffff);
}
TEST_CASE("uint64 from string") {
REQUIRE(StringTo<uint64_t>("0") == 0);
REQUIRE(StringTo<uint64_t>("5") == 5u);
REQUIRE(StringTo<uint64_t>("16") == 16u);
REQUIRE(StringTo<uint64_t>("20") == 20u);
REQUIRE(StringTo<uint64_t>("0x14") == 20u);
REQUIRE(StringTo<uint64_t>("0x15") == 21u);
REQUIRE(StringTo<uint64_t>("0xffffff") == 0xffffff);
}
TEST_CASE("int from string") {
REQUIRE(StringTo<int>("-1") == -1);
REQUIRE(StringTo<int>("-0x1") == -0x1);
REQUIRE(StringTo<int>("-0x1") == -1);
REQUIRE(StringTo<int>("0") == 0);
REQUIRE(StringTo<int>("5") == 5);
REQUIRE(StringTo<int>("16") == 16);
REQUIRE(StringTo<int>("20") == 20);
REQUIRE(StringTo<int>("0x14") == 20);
REQUIRE(StringTo<int>("0x15") == 21);
REQUIRE(StringTo<int>("0xffffff") == 0xffffff);
}
TEST_CASE("std::map of strings") {
std::map<std::string, std::string> m;
m["key"] = "value";
auto s = ToString(m);
REQUIRE(s == "{key: value}");
m["chrusi"] = "musi";
REQUIRE(ToString(m) == "{chrusi: musi, key: value}");
m["test"] = "tree";
REQUIRE(ToString(m) == "{chrusi: musi, key: value, test: tree}");
}
TEST_CASE("Formatting ROI") {
aare::ROI roi;
roi.xmin = 5;
roi.xmax = 159;
roi.ymin = 6;
roi.ymax = 170;
REQUIRE(ToString(roi) == "[5, 159, 6, 170]");
}
TEST_CASE("Streaming of ROI") {
aare::ROI roi;
roi.xmin = 50;
roi.xmax = 109;
roi.ymin = 6;
roi.ymax = 130;
std::ostringstream oss;
oss << roi;
REQUIRE(oss.str() == "[50, 109, 6, 130]");
}
// TODO: After StringTo<scanParameters> is implemented
/*TEST_CASE("Streaming of scanParameters") {
using namespace sls;
{
aare::scanParameters t{};
std::ostringstream oss;
oss << t;
REQUIRE(oss.str() == "[disabled]");
}
{
aare::scanParameters t{defs::VTH2, 500, 1500, 500};
std::ostringstream oss;
oss << t;
REQUIRE(oss.str() == "[enabled\ndac vth2\nstart 500\nstop 1500\nstep "
"500\nsettleTime 1ms\n]");
}
{
aare::scanParameters t{defs::VTH2, 500, 1500, 500,
std::chrono::milliseconds{500}};
std::ostringstream oss;
oss << t;
REQUIRE(oss.str() == "[enabled\ndac vth2\nstart 500\nstop 1500\nstep "
"500\nsettleTime 0.5s\n]");
}
}*/