mirror of
https://github.com/slsdetectorgroup/aare.git
synced 2026-10-20 21:56:19 +02:00
solved merge conflict
This commit is contained in:
commit
9a0fa9cdc4
52 files changed
+401
-175
No files matched your search
@@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest,macos-latest]
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
name: Build and test on Windows
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: python -m pip install ninja numpy matplotlib pytest pytest-check boost-histogram
|
||||
|
||||
# Puts cl.exe on the path so that CMake can use the Ninja generator
|
||||
- uses: ilammy/msvc-dev-cmd@v1
|
||||
|
||||
- name: Configure
|
||||
run: cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DAARE_TESTS=ON -DAARE_PYTHON_BINDINGS=ON -DAARE_WARNINGS_AS_ERRORS=ON
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build
|
||||
|
||||
- name: C++ unit tests
|
||||
run: ctest --test-dir build --output-on-failure -j4
|
||||
|
||||
- name: Python unit tests
|
||||
env:
|
||||
PYTHONPATH: ${{ github.workspace }}\build
|
||||
run: python -m pytest python/tests
|
||||
+39
-21
@@ -208,6 +208,11 @@ if(AARE_FETCH_FMT)
|
||||
CACHE BOOL "")
|
||||
FetchContent_MakeAvailable(fmt)
|
||||
set_property(TARGET fmt PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
if(MSVC)
|
||||
# fmt 12.1.0 calls std::isalpha only to check that ADL finds it and drops
|
||||
# the result, which MSVC's standard library marks [[nodiscard]]
|
||||
target_compile_options(fmt PRIVATE /wd4834)
|
||||
endif()
|
||||
else()
|
||||
find_package(fmt 8 REQUIRED)
|
||||
endif()
|
||||
@@ -254,18 +259,30 @@ target_compile_features(aare_compiler_flags INTERFACE cxx_std_17)
|
||||
# MSVC specific #
|
||||
# ##############################################################################
|
||||
if(MSVC)
|
||||
add_compile_definitions(AARE_MSVC)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
message(STATUS "Release build")
|
||||
target_compile_options(aare_compiler_flags INTERFACE /O2)
|
||||
else()
|
||||
message(STATUS "Debug build")
|
||||
target_compile_options(aare_compiler_flags
|
||||
INTERFACE /Od /Zi /MDd /D_ITERATOR_DEBUG_LEVEL=2)
|
||||
target_link_options(aare_compiler_flags INTERFACE /DEBUG:FULL)
|
||||
endif()
|
||||
target_compile_options(aare_compiler_flags INTERFACE /w # disable warnings
|
||||
# CMake sets the per-configuration optimisation, debug-info and
|
||||
# runtime-library flags itself, so only warnings and conformance here.
|
||||
target_compile_options(
|
||||
aare_compiler_flags
|
||||
INTERFACE /W4 # -Wall -Wextra
|
||||
/permissive- # standard conformance, like CMAKE_CXX_EXTENSIONS OFF
|
||||
/utf-8 # sources are UTF-8
|
||||
/we4715 # not all control paths return a value, like
|
||||
# -Werror=return-type
|
||||
/wd4244 # narrowing conversions: -Wconversion is not enabled
|
||||
/wd4267 # on gcc/clang either
|
||||
/wd4068 # unknown pragma: the GCC diagnostic pragmas
|
||||
/wd4324 # structure padded due to alignas: intended
|
||||
)
|
||||
target_compile_definitions(aare_compiler_flags
|
||||
INTERFACE _CRT_SECURE_NO_WARNINGS)
|
||||
|
||||
if(AARE_WARNINGS_AS_ERRORS)
|
||||
target_compile_options(aare_compiler_flags INTERFACE /WX)
|
||||
endif()
|
||||
|
||||
if(AARE_ASAN)
|
||||
message(WARNING "AARE_ASAN is not supported with MSVC. Ignoring.")
|
||||
endif()
|
||||
|
||||
else()
|
||||
# ############################################################################
|
||||
@@ -318,22 +335,22 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(AARE_ASAN)
|
||||
message(STATUS "AddressSanitizer enabled")
|
||||
target_compile_options(
|
||||
aare_compiler_flags INTERFACE -fsanitize=address,undefined,pointer-compare
|
||||
-fno-omit-frame-pointer)
|
||||
target_link_libraries(
|
||||
aare_compiler_flags INTERFACE -fsanitize=address,undefined,pointer-compare
|
||||
-fno-omit-frame-pointer)
|
||||
endif()
|
||||
|
||||
endif() # GCC/Clang specific
|
||||
|
||||
if(AARE_PYTHON_BINDINGS)
|
||||
add_subdirectory(python)
|
||||
endif()
|
||||
|
||||
if(AARE_ASAN)
|
||||
message(STATUS "AddressSanitizer enabled")
|
||||
target_compile_options(
|
||||
aare_compiler_flags INTERFACE -fsanitize=address,undefined,pointer-compare
|
||||
-fno-omit-frame-pointer)
|
||||
target_link_libraries(
|
||||
aare_compiler_flags INTERFACE -fsanitize=address,undefined,pointer-compare
|
||||
-fno-omit-frame-pointer)
|
||||
endif()
|
||||
|
||||
if(AARE_TESTS)
|
||||
enable_testing()
|
||||
add_subdirectory(tests)
|
||||
@@ -485,6 +502,7 @@ if(AARE_TESTS)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/hist/PixelHistogram.test.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/hist/PedestalTrackingPixelHistogram.test.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/JungfrauDataFile.test.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/logger.test.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/MultiThreadedFileReader.test.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/NumpyFile.test.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/NumpyHelpers.test.cpp
|
||||
|
||||
+9
-1
@@ -1,7 +1,15 @@
|
||||
# Release notes
|
||||
|
||||
### New Features:
|
||||
## Next:
|
||||
|
||||
### New Features:
|
||||
|
||||
- Added the Python ``xy`` type with ``row`` and ``col`` fields, enabling access
|
||||
to ``RawFile.geometry``, ``RawMasterFile.detector_layout``, and
|
||||
``RawMasterFile.udp_interfaces_per_module``. It unpacks as ``row, col``.
|
||||
- Added Windows wheels (``win_amd64``, Python 3.12 to 3.14) to the wheel
|
||||
build, so releases publish them to PyPI alongside the Linux and macOS
|
||||
wheels.
|
||||
- Added ``read_columns`` to JungfrauDataFile to only read selected columns
|
||||
|
||||
## 2026.9.30
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using aare::ssize_t;
|
||||
|
||||
struct TestCase {
|
||||
std::string name;
|
||||
double true_A;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
using aare::NDArray;
|
||||
using aare::ssize_t;
|
||||
|
||||
constexpr ssize_t size = 1024;
|
||||
class TwoArrays : public benchmark::Fixture {
|
||||
|
||||
@@ -83,7 +83,7 @@ struct Cluster {
|
||||
data[cluster_center_index - ClusterSizeX] +
|
||||
data[cluster_center_index - 1 - ClusterSizeX];
|
||||
// subcluster top right from center
|
||||
if (ClusterSizeX > 2) {
|
||||
if constexpr (ClusterSizeX > 2) {
|
||||
sum_2x2_subcluster[1] =
|
||||
data[cluster_center_index] +
|
||||
data[cluster_center_index + 1] +
|
||||
@@ -91,7 +91,7 @@ struct Cluster {
|
||||
data[cluster_center_index - ClusterSizeX + 1];
|
||||
}
|
||||
// subcluster bottom left from center
|
||||
if (ClusterSizeY > 2) {
|
||||
if constexpr (ClusterSizeY > 2) {
|
||||
sum_2x2_subcluster[2] =
|
||||
data[cluster_center_index] +
|
||||
data[cluster_center_index - 1] +
|
||||
@@ -99,7 +99,7 @@ struct Cluster {
|
||||
data[cluster_center_index + ClusterSizeX - 1];
|
||||
}
|
||||
// subcluster bottom right from center
|
||||
if (ClusterSizeX > 2 && ClusterSizeY > 2) {
|
||||
if constexpr (ClusterSizeX > 2 && ClusterSizeY > 2) {
|
||||
sum_2x2_subcluster[3] =
|
||||
data[cluster_center_index] +
|
||||
data[cluster_center_index + 1] +
|
||||
|
||||
@@ -1,10 +1,29 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
#pragma once
|
||||
#include "aare/defs.hpp"
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <filesystem>
|
||||
|
||||
namespace aare {
|
||||
|
||||
// MSVC's long is 32 bits, so fseek/ftell stop working past 2 GB there
|
||||
inline int fseek64(FILE *fp, int64_t offset, int whence) {
|
||||
#ifdef _WIN32
|
||||
return _fseeki64(fp, offset, whence);
|
||||
#else
|
||||
return fseek(fp, static_cast<long>(offset), whence);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int64_t ftell64(FILE *fp) {
|
||||
#ifdef _WIN32
|
||||
return _ftelli64(fp);
|
||||
#else
|
||||
return ftell(fp);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief RAII wrapper for FILE pointer
|
||||
*/
|
||||
@@ -22,7 +41,7 @@ class FilePtr {
|
||||
FILE *get();
|
||||
ssize_t tell();
|
||||
void seek(ssize_t offset, int whence = SEEK_SET) {
|
||||
if (fseek(fp_, offset, whence) != 0)
|
||||
if (fseek64(fp_, offset, whence) != 0)
|
||||
throw std::runtime_error("Error seeking in file");
|
||||
}
|
||||
std::string error_msg();
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#pragma once
|
||||
#include "aare/Dtype.hpp"
|
||||
#include "aare/FileInterface.hpp"
|
||||
#include "aare/FilePtr.hpp"
|
||||
#include "aare/NumpyHelpers.hpp"
|
||||
#include "aare/defs.hpp"
|
||||
|
||||
@@ -77,7 +78,7 @@ class NumpyFile : public FileInterface {
|
||||
*/
|
||||
template <typename T, size_t NDim> NDArray<T, NDim> load() {
|
||||
NDArray<T, NDim> arr(make_shape<NDim>(m_header.shape));
|
||||
if (fseek(fp, static_cast<long>(header_size), SEEK_SET)) {
|
||||
if (fseek64(fp, header_size, SEEK_SET)) {
|
||||
throw std::runtime_error(LOCATION +
|
||||
"Error seeking to the start of the data");
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
@@ -13,6 +14,10 @@
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
#include <sys/types.h> // ::ssize_t
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief LOCATION macro to get the current location in the code
|
||||
*/
|
||||
@@ -54,6 +59,18 @@
|
||||
|
||||
namespace aare {
|
||||
|
||||
/**
|
||||
* Signed size and index type used throughout the library (shapes, strides,
|
||||
* frame indices, ROI coordinates). On POSIX this is the platform's ssize_t,
|
||||
* so nothing changes for existing code. MSVC has no ssize_t, so there it is
|
||||
* std::ptrdiff_t, which is the same type as Py_ssize_t and NumPy's npy_intp.
|
||||
*/
|
||||
#if defined(_MSC_VER)
|
||||
using ssize_t = std::ptrdiff_t;
|
||||
#else
|
||||
using ssize_t = ::ssize_t;
|
||||
#endif
|
||||
|
||||
inline constexpr size_t bits_per_byte = 8;
|
||||
|
||||
void assert_failed(const std::string &msg);
|
||||
|
||||
+49
-21
@@ -2,9 +2,12 @@
|
||||
#pragma once
|
||||
/*Utility to log to console*/
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <sys/time.h>
|
||||
#include <string>
|
||||
|
||||
namespace aare {
|
||||
|
||||
@@ -55,12 +58,53 @@ enum TLogLevel {
|
||||
#define __AT__ \
|
||||
std::string(__FILE__) + std::string("::") + std::string(__func__) + \
|
||||
std::string("(): ")
|
||||
#define __SHORT_FORM_OF_FILE__ \
|
||||
(strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
|
||||
#define __SHORT_FORM_OF_FILE__ aare::short_file_name(__FILE__)
|
||||
#define __SHORT_AT__ \
|
||||
std::string(__SHORT_FORM_OF_FILE__) + std::string("::") + \
|
||||
std::string(__func__) + std::string("(): ")
|
||||
|
||||
/**
|
||||
* @brief Strip the directory part of a path, accepting both '/' and '\\' as
|
||||
* separators so that __FILE__ is shortened the same way on every platform.
|
||||
*/
|
||||
inline const char *short_file_name(const char *path) noexcept {
|
||||
const char *base = path;
|
||||
for (const char *p = path; *p != '\0'; ++p) {
|
||||
if (*p == '/' || *p == '\\')
|
||||
base = p + 1;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Local wall-clock time as HH:MM:SS.mmm (strftime "%X" plus
|
||||
* milliseconds), built from std::chrono so it works on every platform.
|
||||
*/
|
||||
inline std::string log_timestamp() {
|
||||
using namespace std::chrono;
|
||||
const auto now = system_clock::now();
|
||||
const time_t t = system_clock::to_time_t(now);
|
||||
const auto ms = duration_cast<milliseconds>(now.time_since_epoch()) % 1000;
|
||||
|
||||
tm local{};
|
||||
#if defined(_MSC_VER)
|
||||
localtime_s(&local, &t);
|
||||
#else
|
||||
localtime_r(&t, &local);
|
||||
#endif
|
||||
|
||||
constexpr size_t buffer_len = 12;
|
||||
char buffer[buffer_len];
|
||||
if (strftime(buffer, buffer_len, "%X", &local) == 0)
|
||||
buffer[0] = '\0';
|
||||
|
||||
constexpr size_t result_len = 100;
|
||||
char result[result_len];
|
||||
snprintf(result, result_len, "%s.%03d", buffer,
|
||||
static_cast<int>(ms.count()));
|
||||
return result;
|
||||
}
|
||||
|
||||
class Logger {
|
||||
std::ostringstream os;
|
||||
TLogLevel m_level = AARE_LOG_LEVEL;
|
||||
@@ -111,28 +155,12 @@ class Logger {
|
||||
return os;
|
||||
}
|
||||
|
||||
static std::string Timestamp() {
|
||||
constexpr size_t buffer_len = 12;
|
||||
char buffer[buffer_len];
|
||||
time_t t;
|
||||
::time(&t);
|
||||
tm r;
|
||||
strftime(buffer, buffer_len, "%X", localtime_r(&t, &r));
|
||||
buffer[buffer_len - 1] = '\0';
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
constexpr size_t result_len = 100;
|
||||
char result[result_len];
|
||||
snprintf(result, result_len, "%s.%03ld", buffer,
|
||||
static_cast<long>(tv.tv_usec) / 1000);
|
||||
result[result_len - 1] = '\0';
|
||||
return result;
|
||||
}
|
||||
static std::string Timestamp() { return log_timestamp(); }
|
||||
};
|
||||
|
||||
// TODO! Do we need to keep the runtime option?
|
||||
#define LOG(level) \
|
||||
if (level > AARE_LOG_LEVEL) \
|
||||
if constexpr (level > AARE_LOG_LEVEL) \
|
||||
; \
|
||||
else if (level > aare::Logger::ReportingLevel()) \
|
||||
; \
|
||||
|
||||
@@ -19,7 +19,7 @@ T string_to(const std::string &t, const std::string &unit) {
|
||||
double tval{0};
|
||||
try {
|
||||
tval = std::stod(t);
|
||||
} catch (const std::invalid_argument &e) {
|
||||
} catch (const std::invalid_argument &) {
|
||||
throw std::runtime_error("Could not convert string to time");
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,9 @@ build = "cp{312,313,314}-manylinux_x86_64"
|
||||
build = "cp{312,313,314}-macosx_*"
|
||||
archs = ["arm64"]
|
||||
|
||||
[tool.cibuildwheel.windows]
|
||||
build = "cp{312,313,314}-win_amd64"
|
||||
|
||||
|
||||
[tool.scikit-build]
|
||||
build.verbose = true
|
||||
|
||||
@@ -25,6 +25,7 @@ from ._aare import Pedestal_d, Pedestal_f, ClusterFinder_Cluster3x3i, VarCluster
|
||||
from ._aare import DetectorType, FrameDiscardPolicy, ReadoutMode
|
||||
from ._aare import hitmap
|
||||
from ._aare import ROI
|
||||
from ._aare import xy
|
||||
from ._aare import corner
|
||||
|
||||
from ._aare import UDPPortPosition
|
||||
|
||||
@@ -13,9 +13,6 @@ namespace py = pybind11;
|
||||
|
||||
using namespace aare;
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
|
||||
template <typename Type, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
|
||||
typename CoordType>
|
||||
void define_Cluster(py::module &m, const std::string &typestr) {
|
||||
@@ -140,5 +137,3 @@ void reduce_to_2x2(py::module &m) {
|
||||
row-major order.
|
||||
)doc");
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
@@ -20,9 +20,6 @@ namespace py = pybind11;
|
||||
|
||||
using namespace aare;
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
|
||||
template <typename T, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
|
||||
typename CoordType = uint16_t>
|
||||
void define_ClusterCollector(py::module &m, const std::string &typestr) {
|
||||
@@ -42,5 +39,3 @@ void define_ClusterCollector(py::module &m, const std::string &typestr) {
|
||||
},
|
||||
py::return_value_policy::take_ownership);
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
@@ -13,11 +13,6 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
// Disable warnings for unused parameters, as we ignore some
|
||||
// in the __exit__ method
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
|
||||
namespace py = pybind11;
|
||||
using namespace ::aare;
|
||||
|
||||
@@ -171,14 +166,12 @@ void define_ClusterFile(py::module &m, const std::string &typestr) {
|
||||
.def("__enter__", [](ClusterFile<ClusterType> &self) { return &self; })
|
||||
.def("__exit__",
|
||||
[](ClusterFile<ClusterType> &self,
|
||||
const std::optional<pybind11::type> &exc_type,
|
||||
const std::optional<pybind11::object> &exc_value,
|
||||
const std::optional<pybind11::object> &traceback) {
|
||||
self.close();
|
||||
})
|
||||
[[maybe_unused]] const std::optional<pybind11::type> &exc_type,
|
||||
[[maybe_unused]] const std::optional<pybind11::object>
|
||||
&exc_value,
|
||||
[[maybe_unused]] const std::optional<pybind11::object>
|
||||
&traceback) { self.close(); })
|
||||
.def("__iter__", [](ClusterFile<ClusterType> &self) { return &self; })
|
||||
.def("__next__",
|
||||
[](File &self) { return ChunkIterator(self.chunks()).next(); });
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
@@ -17,9 +17,6 @@
|
||||
namespace py = pybind11;
|
||||
using namespace aare;
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
|
||||
template <typename T, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
|
||||
typename CoordType = uint16_t>
|
||||
void define_ClusterFileSink(py::module &m, const std::string &typestr) {
|
||||
@@ -34,5 +31,3 @@ void define_ClusterFileSink(py::module &m, const std::string &typestr) {
|
||||
const std::filesystem::path &>())
|
||||
.def("stop", &ClusterFileSink<ClusterType>::stop);
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
@@ -20,9 +20,6 @@ namespace py = pybind11;
|
||||
|
||||
using namespace aare;
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
|
||||
template <typename T, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
|
||||
typename CoordType = uint16_t>
|
||||
void define_ClusterFinder(py::module &m, const std::string &typestr) {
|
||||
@@ -92,5 +89,3 @@ void define_ClusterFinder(py::module &m, const std::string &typestr) {
|
||||
},
|
||||
py::arg("frame").noconvert(), py::arg("frame_number") = 0);
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
@@ -20,9 +20,6 @@ namespace py = pybind11;
|
||||
|
||||
using namespace aare;
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
|
||||
template <typename T, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
|
||||
typename CoordType = uint16_t>
|
||||
void define_ClusterFinderMT(py::module &m, const std::string &typestr) {
|
||||
@@ -55,7 +52,8 @@ void define_ClusterFinderMT(py::module &m, const std::string &typestr) {
|
||||
py::arg("frame").noconvert(), py::arg("frame_number") = 0)
|
||||
.def_property_readonly(
|
||||
"cluster_size",
|
||||
[](ClusterFinderMT<ClusterType, uint16_t, pd_type> &self) {
|
||||
[]([[maybe_unused]] ClusterFinderMT<ClusterType, uint16_t, pd_type>
|
||||
&self) {
|
||||
return py::make_tuple(ClusterSizeX, ClusterSizeY);
|
||||
})
|
||||
.def("clear_pedestal",
|
||||
@@ -93,5 +91,3 @@ void define_ClusterFinderMT(py::module &m, const std::string &typestr) {
|
||||
py::arg("nSigma"),
|
||||
R"(sets the number of sigma for all cluster finders.)");
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
@@ -18,9 +18,6 @@ namespace py = pybind11;
|
||||
|
||||
using namespace aare;
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
|
||||
template <typename Type, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
|
||||
typename CoordType = uint16_t>
|
||||
void define_ClusterVector(py::module &m, const std::string &typestr) {
|
||||
@@ -123,8 +120,8 @@ void define_ClusterVector(py::module &m, const std::string &typestr) {
|
||||
"padding.")
|
||||
.def_property_readonly(
|
||||
"fmt",
|
||||
[typestr](ClusterVector<ClusterType> &self) {
|
||||
return fmt_format<ClusterType>;
|
||||
[typestr]([[maybe_unused]] ClusterVector<ClusterType> &self) {
|
||||
return fmt_format<ClusterType>();
|
||||
},
|
||||
"PEP 3118 format string for one stored cluster.")
|
||||
|
||||
@@ -145,11 +142,11 @@ void define_ClusterVector(py::module &m, const std::string &typestr) {
|
||||
.def_buffer(
|
||||
[typestr](ClusterVector<ClusterType> &self) -> py::buffer_info {
|
||||
return py::buffer_info(
|
||||
self.data(), /* Pointer to buffer */
|
||||
self.item_size(), /* Size of one scalar */
|
||||
fmt_format<ClusterType>, /* Format descriptor */
|
||||
1, /* Number of dimensions */
|
||||
{self.size()}, /* Buffer dimensions */
|
||||
self.data(), /* Pointer to buffer */
|
||||
self.item_size(), /* Size of one scalar */
|
||||
fmt_format<ClusterType>(), /* Format descriptor */
|
||||
1, /* Number of dimensions */
|
||||
{self.size()}, /* Buffer dimensions */
|
||||
{self.item_size()} /* Strides (in bytes) for each index */
|
||||
);
|
||||
});
|
||||
@@ -228,5 +225,3 @@ void define_3x3_reduction(py::module &m) {
|
||||
)doc",
|
||||
py::arg("clustervector"));
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
@@ -1,4 +1,5 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
#include <pybind11/operators.h>
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
|
||||
@@ -77,6 +78,21 @@ void define_defs_bindings(py::module &m) {
|
||||
self.ymin == other.ymin && self.ymax == other.ymax;
|
||||
});
|
||||
|
||||
py::class_<xy>(m, "xy")
|
||||
.def(py::init<uint32_t, uint32_t>(), py::arg("row"), py::arg("col"))
|
||||
.def_readwrite("row", &xy::row)
|
||||
.def_readwrite("col", &xy::col)
|
||||
.def("__repr__",
|
||||
[](const xy &self) {
|
||||
return fmt::format("xy(row={}, col={})", self.row, self.col);
|
||||
})
|
||||
.def("__iter__",
|
||||
[](const xy &self) {
|
||||
return py::iter(py::make_tuple(self.row, self.col));
|
||||
})
|
||||
.def(py::self == py::self)
|
||||
.def(py::self != py::self);
|
||||
|
||||
py::enum_<DetectorType>(m, "DetectorType")
|
||||
.value("Jungfrau", DetectorType::Jungfrau)
|
||||
.value("Eiger", DetectorType::Eiger)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <pybind11/stl/filesystem.h>
|
||||
|
||||
namespace py = pybind11;
|
||||
using aare::ssize_t;
|
||||
|
||||
inline py::dtype multi_threaded_reader_numpy_dtype(const aare::Dtype &dtype) {
|
||||
using aare::Dtype;
|
||||
|
||||
@@ -318,7 +318,14 @@ void define_raw_file_io_bindings(py::module &m) {
|
||||
Cols for the given ROI.
|
||||
)")
|
||||
.def_property_readonly("bitdepth", &RawFile::bitdepth)
|
||||
.def_property_readonly("geometry", &RawFile::geometry)
|
||||
.def_property_readonly("geometry", &RawFile::geometry, R"(
|
||||
Number of modules along each axis of the detector.
|
||||
|
||||
Returns
|
||||
-------
|
||||
xy
|
||||
Module rows and columns.
|
||||
)")
|
||||
.def_property_readonly("detector_type", &RawFile::detector_type)
|
||||
.def_property_readonly("master", &RawFile::master)
|
||||
.def_property_readonly("n_modules", &RawFile::n_modules)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <pybind11/stl_bind.h>
|
||||
|
||||
namespace py = pybind11;
|
||||
using aare::ssize_t;
|
||||
|
||||
template <typename DataType>
|
||||
py::array_t<DataType>
|
||||
|
||||
+7
-11
@@ -21,11 +21,6 @@
|
||||
namespace py = pybind11;
|
||||
using namespace ::aare;
|
||||
|
||||
// Disable warnings for unused parameters, as we ignore some
|
||||
// in the __exit__ method
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
|
||||
void define_file_io_bindings(py::module &m) {
|
||||
|
||||
PYBIND11_NUMPY_DTYPE(DetectorHeader, frameNumber, expLength, packetNumber,
|
||||
@@ -122,9 +117,12 @@ void define_file_io_bindings(py::module &m) {
|
||||
})
|
||||
.def("__enter__", [](File &self) { return &self; })
|
||||
.def("__exit__",
|
||||
[](File &self, const std::optional<pybind11::type> &exc_type,
|
||||
const std::optional<pybind11::object> &exc_value,
|
||||
const std::optional<pybind11::object> &traceback) {
|
||||
[]([[maybe_unused]] File &self,
|
||||
[[maybe_unused]] const std::optional<pybind11::type> &exc_type,
|
||||
[[maybe_unused]] const std::optional<pybind11::object>
|
||||
&exc_value,
|
||||
[[maybe_unused]] const std::optional<pybind11::object>
|
||||
&traceback) {
|
||||
// self.close();
|
||||
})
|
||||
.def("__iter__", [](File &self) { return &self; })
|
||||
@@ -146,7 +144,7 @@ void define_file_io_bindings(py::module &m) {
|
||||
self.read_into(
|
||||
reinterpret_cast<std::byte *>(image.mutable_data()));
|
||||
return image;
|
||||
} catch (std::runtime_error &e) {
|
||||
} catch (std::runtime_error &) {
|
||||
throw py::stop_iteration();
|
||||
}
|
||||
});
|
||||
@@ -160,6 +158,4 @@ void define_file_io_bindings(py::module &m) {
|
||||
.def_property_readonly("start", &ScanParameters::start)
|
||||
.def_property_readonly("stop", &ScanParameters::stop)
|
||||
.def_property_readonly("step", &ScanParameters::step);
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace py = pybind11;
|
||||
using namespace pybind11::literals;
|
||||
using aare::ssize_t;
|
||||
|
||||
template <typename Model>
|
||||
py::object
|
||||
|
||||
@@ -15,11 +15,6 @@
|
||||
namespace py = pybind11;
|
||||
using namespace ::aare;
|
||||
|
||||
// Disable warnings for unused parameters, as we ignore some
|
||||
// in the __exit__ method
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
|
||||
auto read_dat_frame(JungfrauDataFile &self) {
|
||||
py::array_t<JungfrauDataHeader> header(1);
|
||||
py::array_t<uint16_t> image({self.rows(), self.cols()});
|
||||
@@ -119,20 +114,20 @@ void define_jungfrau_data_file_io_bindings(py::module &m) {
|
||||
)")
|
||||
.def("__enter__", [](JungfrauDataFile &self) { return &self; })
|
||||
.def("__exit__",
|
||||
[](JungfrauDataFile &self,
|
||||
const std::optional<pybind11::type> &exc_type,
|
||||
const std::optional<pybind11::object> &exc_value,
|
||||
const std::optional<pybind11::object> &traceback) {
|
||||
[]([[maybe_unused]] JungfrauDataFile &self,
|
||||
[[maybe_unused]] const std::optional<pybind11::type> &exc_type,
|
||||
[[maybe_unused]] const std::optional<pybind11::object>
|
||||
&exc_value,
|
||||
[[maybe_unused]] const std::optional<pybind11::object>
|
||||
&traceback) {
|
||||
// self.close();
|
||||
})
|
||||
.def("__iter__", [](JungfrauDataFile &self) { return &self; })
|
||||
.def("__next__", [](JungfrauDataFile &self) {
|
||||
try {
|
||||
return read_dat_frame(self);
|
||||
} catch (std::runtime_error &e) {
|
||||
} catch (std::runtime_error &) {
|
||||
throw py::stop_iteration();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
@@ -112,8 +112,13 @@ struct fmt_format_trait<Cluster<T, ClusterSizeX, ClusterSizeY, CoordType>> {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ClusterType>
|
||||
auto fmt_format = fmt_format_trait<ClusterType>::value();
|
||||
// Function-local static rather than a variable template: MSVC does not run
|
||||
// the dynamic initializer of a variable template instantiated from inside
|
||||
// another template, which left the format string empty.
|
||||
template <typename ClusterType> const std::string &fmt_format() {
|
||||
static const std::string value = fmt_format_trait<ClusterType>::value();
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to allocate image data given item size and shape
|
||||
|
||||
@@ -67,9 +67,23 @@ void define_raw_master_file_bindings(py::module &m) {
|
||||
.def_property_readonly("total_frames_expected",
|
||||
&RawMasterFile::total_frames_expected)
|
||||
.def_property_readonly("detector_layout",
|
||||
&RawMasterFile::detector_layout)
|
||||
&RawMasterFile::detector_layout, R"(
|
||||
Number of modules along each axis of the detector
|
||||
|
||||
Returns
|
||||
----------
|
||||
xy
|
||||
Module rows and columns
|
||||
)")
|
||||
.def_property_readonly("udp_interfaces_per_module",
|
||||
&RawMasterFile::udp_interfaces_per_module)
|
||||
&RawMasterFile::udp_interfaces_per_module, R"(
|
||||
Number of UDP interfaces along each axis of a module
|
||||
|
||||
Returns
|
||||
----------
|
||||
xy
|
||||
UDP interface rows and columns
|
||||
)")
|
||||
.def_property_readonly("analog_samples", &RawMasterFile::analog_samples,
|
||||
R"(
|
||||
Number of analog samples
|
||||
|
||||
@@ -61,11 +61,6 @@ auto read_n_frames_from_RawSubFile(RawSubFile &self, size_t n_frames) {
|
||||
return py::make_tuple(header, image);
|
||||
}
|
||||
|
||||
// Disable warnings for unused parameters, as we ignore some
|
||||
// in the __exit__ method
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
|
||||
void define_raw_sub_file_io_bindings(py::module &m) {
|
||||
py::class_<RawSubFile>(m, "RawSubFile")
|
||||
.def(py::init<const std::filesystem::path &, DetectorType, size_t,
|
||||
@@ -89,17 +84,18 @@ void define_raw_sub_file_io_bindings(py::module &m) {
|
||||
})
|
||||
.def("__enter__", [](RawSubFile &self) { return &self; })
|
||||
.def("__exit__",
|
||||
[](RawSubFile &self, const std::optional<pybind11::type> &exc_type,
|
||||
const std::optional<pybind11::object> &exc_value,
|
||||
const std::optional<pybind11::object> &traceback) {})
|
||||
[]([[maybe_unused]] RawSubFile &self,
|
||||
[[maybe_unused]] const std::optional<pybind11::type> &exc_type,
|
||||
[[maybe_unused]] const std::optional<pybind11::object>
|
||||
&exc_value,
|
||||
[[maybe_unused]] const std::optional<pybind11::object>
|
||||
&traceback) {})
|
||||
.def("__iter__", [](RawSubFile &self) { return &self; })
|
||||
.def("__next__", [](RawSubFile &self) {
|
||||
try {
|
||||
return read_frame_from_RawSubFile(self);
|
||||
} catch (std::runtime_error &e) {
|
||||
} catch (std::runtime_error &) {
|
||||
throw py::stop_iteration();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
@@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
import pytest
|
||||
import json
|
||||
from aare import File, RawFile, RawSubFile, DetectorType, ROI, UDPPortPosition
|
||||
from aare import File, RawFile, RawSubFile, DetectorType, ROI, UDPPortPosition, xy
|
||||
import numpy as np
|
||||
|
||||
|
||||
@@ -237,6 +237,20 @@ def test_raw_frame_count_across_rois(small_raw_file, short_module):
|
||||
reader.read_roi(roi_index)
|
||||
|
||||
|
||||
def test_raw_file_geometry(small_raw_file):
|
||||
metadata = json.loads(small_raw_file.read_text())
|
||||
metadata["Geometry"] = {"x": 1, "y": 2}
|
||||
small_raw_file.write_text(json.dumps(metadata))
|
||||
for index in range(2):
|
||||
data = (small_raw_file.parent / f"run_d0_f{index}_0.raw").read_bytes()
|
||||
(small_raw_file.parent / f"run_d1_f{index}_0.raw").write_bytes(data)
|
||||
|
||||
reader = RawFile(small_raw_file)
|
||||
assert reader.geometry == xy(row=2, col=1)
|
||||
assert reader.master.detector_layout == xy(row=2, col=1)
|
||||
assert reader.master.udp_interfaces_per_module == xy(row=1, col=1)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("disabled_port", [0, 1])
|
||||
def test_raw_frame_count_with_disabled_udp_port(small_raw_file, disabled_port):
|
||||
metadata = json.loads(small_raw_file.read_text())
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
from aare import xy
|
||||
|
||||
|
||||
def test_xy_fields():
|
||||
layout = xy(row=2, col=3)
|
||||
assert layout.row == 2
|
||||
assert layout.col == 3
|
||||
|
||||
layout.row = 4
|
||||
assert layout.row == 4
|
||||
|
||||
|
||||
def test_xy_unpacks_as_row_col():
|
||||
row, col = xy(2, 3)
|
||||
assert (row, col) == (2, 3)
|
||||
|
||||
|
||||
def test_xy_comparison():
|
||||
assert xy(2, 3) == xy(2, 3)
|
||||
assert xy(2, 3) != xy(3, 2)
|
||||
assert xy(2, 3) != (2, 3)
|
||||
|
||||
|
||||
def test_xy_repr():
|
||||
assert repr(xy(2, 3)) == "xy(row=2, col=3)"
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
using aare::Cluster;
|
||||
using aare::ClusterVector;
|
||||
using aare::ssize_t;
|
||||
using C1 = Cluster<int32_t, 2, 2>;
|
||||
|
||||
TEST_CASE("A newly created ClusterVector is empty") {
|
||||
@@ -180,7 +181,8 @@ TEST_CASE("Summing 3x1 clusters of int64") {
|
||||
|
||||
Cluster<int32_t, 3, 1> c3 = {11, 12, {13, 14, 15}};
|
||||
cv.push_back(c3);
|
||||
REQUIRE(cv.capacity() == 4);
|
||||
// growth factor is implementation defined (2x libstdc++, 1.5x MSVC)
|
||||
REQUIRE(cv.capacity() >= 3);
|
||||
REQUIRE(cv.size() == 3);
|
||||
|
||||
/*
|
||||
@@ -236,7 +238,8 @@ TEST_CASE("Push back more than initial capacity") {
|
||||
Cluster<int32_t, 2, 2> c3 = {11, 12, {13, 14, 15, 16}};
|
||||
cv.push_back(c3);
|
||||
REQUIRE(cv.size() == 3);
|
||||
REQUIRE(cv.capacity() == 4);
|
||||
// growth factor is implementation defined (2x libstdc++, 1.5x MSVC)
|
||||
REQUIRE(cv.capacity() >= 3);
|
||||
|
||||
Cluster<int32_t, 2, 2> *ptr =
|
||||
reinterpret_cast<Cluster<int32_t, 2, 2> *>(cv.data());
|
||||
|
||||
+1
-1
@@ -159,7 +159,7 @@ Dtype Dtype::from_bitdepth(uint8_t bitdepth) {
|
||||
std::string Dtype::to_string() const {
|
||||
|
||||
char ec{};
|
||||
if (endian::native == endian::little)
|
||||
if constexpr (endian::native == endian::little)
|
||||
ec = '<';
|
||||
else
|
||||
ec = '>';
|
||||
|
||||
+3
-3
@@ -9,10 +9,10 @@ namespace aare {
|
||||
|
||||
FilePtr::FilePtr(const std::filesystem::path &fname,
|
||||
const std::string &mode = "rb") {
|
||||
fp_ = fopen(fname.c_str(), mode.c_str());
|
||||
fp_ = fopen(fname.string().c_str(), mode.c_str());
|
||||
if (!fp_)
|
||||
throw std::runtime_error(
|
||||
fmt::format("Could not open: {}", fname.c_str()));
|
||||
fmt::format("Could not open: {}", fname.string()));
|
||||
}
|
||||
|
||||
FilePtr::FilePtr(FilePtr &&other) { std::swap(fp_, other.fp_); }
|
||||
@@ -27,7 +27,7 @@ FilePtr::operator bool() const noexcept { return fp_ != nullptr; }
|
||||
FILE *FilePtr::get() { return fp_; }
|
||||
|
||||
ssize_t FilePtr::tell() {
|
||||
auto pos = ftell(fp_);
|
||||
auto pos = ftell64(fp_);
|
||||
if (pos == -1)
|
||||
throw std::runtime_error(
|
||||
fmt::format("Error getting file position: {}", error_msg()));
|
||||
|
||||
@@ -174,7 +174,7 @@ void JungfrauDataFile::find_frame_size(const std::filesystem::path &fname) {
|
||||
|
||||
void JungfrauDataFile::parse_fname(const std::filesystem::path &fname) {
|
||||
m_path = fname.parent_path();
|
||||
m_base_name = fname.stem();
|
||||
m_base_name = fname.stem().string();
|
||||
|
||||
// find file index, then remove if from the base name
|
||||
if (auto pos = m_base_name.find_last_of('_'); pos != std::string::npos) {
|
||||
@@ -259,7 +259,7 @@ JungfrauDataHeader JungfrauDataFile::read_header() {
|
||||
throw std::runtime_error(LOCATION + "Could not read header from file" +
|
||||
m_fp.error_msg());
|
||||
}
|
||||
m_fp.seek(-header_size, SEEK_CUR);
|
||||
m_fp.seek(-static_cast<ssize_t>(header_size), SEEK_CUR);
|
||||
return header;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ using aare::File;
|
||||
using aare::FileConfig;
|
||||
using aare::Frame;
|
||||
using aare::NumpyFile;
|
||||
using aare::ssize_t;
|
||||
using aare::experimental::MultiThreadedFileReader;
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
using aare::NDArray;
|
||||
using aare::NDView;
|
||||
using aare::Shape;
|
||||
using aare::ssize_t;
|
||||
|
||||
TEST_CASE("Initial size is zero if no size is specified") {
|
||||
NDArray<double> a;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
using aare::NDView;
|
||||
using aare::num_elements;
|
||||
using aare::Shape;
|
||||
using aare::ssize_t;
|
||||
|
||||
static_assert(std::is_convertible_v<NDView<int, 2>, NDView<const int, 2>>);
|
||||
static_assert(!std::is_convertible_v<NDView<const int, 2>, NDView<int, 2>>);
|
||||
|
||||
+7
-8
@@ -28,8 +28,7 @@ NumpyFile::NumpyFile(const std::filesystem::path &fname,
|
||||
throw std::runtime_error(
|
||||
fmt::format("Could not open: {} for reading", fname.string()));
|
||||
}
|
||||
initial_header_len = aare::NumpyHelpers::write_header(
|
||||
std::filesystem::path(fname.c_str()), m_header);
|
||||
initial_header_len = aare::NumpyHelpers::write_header(fname, m_header);
|
||||
}
|
||||
m_pixels_per_frame =
|
||||
std::accumulate(m_header.shape.begin() + 1, m_header.shape.end(), 1,
|
||||
@@ -46,7 +45,7 @@ void NumpyFile::write_impl(void *data, uint64_t size) {
|
||||
if (!(m_mode == "w" || m_mode == "a")) {
|
||||
throw std::invalid_argument("File not open for writing");
|
||||
}
|
||||
if (fseek(fp, 0, SEEK_END))
|
||||
if (fseek64(fp, 0, SEEK_END))
|
||||
throw std::runtime_error("Could not seek to end of file");
|
||||
size_t const rc = fwrite(data, size, 1, fp);
|
||||
if (rc != 1) {
|
||||
@@ -68,8 +67,8 @@ void NumpyFile::get_frame_into(size_t frame_number, std::byte *image_buf) {
|
||||
if (frame_number > m_header.shape[0]) {
|
||||
throw std::invalid_argument("Frame number out of range");
|
||||
}
|
||||
if (fseek(fp, header_size + frame_number * m_bytes_per_frame,
|
||||
SEEK_SET)) // NOLINT
|
||||
if (fseek64(fp, header_size + frame_number * m_bytes_per_frame,
|
||||
SEEK_SET)) // NOLINT
|
||||
throw std::runtime_error("Could not seek to frame");
|
||||
|
||||
size_t const rc = fread(image_buf, m_bytes_per_frame, 1, fp);
|
||||
@@ -101,15 +100,15 @@ void NumpyFile::read_into(std::byte *image_buf, size_t n_frames) {
|
||||
NumpyFile::~NumpyFile() noexcept {
|
||||
if (m_mode == "w" || m_mode == "a") {
|
||||
// determine number of frames
|
||||
if (fseek(fp, 0, SEEK_END)) {
|
||||
if (fseek64(fp, 0, SEEK_END)) {
|
||||
std::cout << "Could not seek to end of file" << std::endl;
|
||||
}
|
||||
size_t const file_size = ftell(fp);
|
||||
size_t const file_size = ftell64(fp);
|
||||
size_t const data_size = file_size - initial_header_len;
|
||||
size_t const n_frames = data_size / m_bytes_per_frame;
|
||||
// update number of frames in header (first element of shape)
|
||||
m_header.shape[0] = n_frames;
|
||||
if (fseek(fp, 0, SEEK_SET)) {
|
||||
if (fseek64(fp, 0, SEEK_SET)) {
|
||||
std::cout << "Could not seek to beginning of file" << std::endl;
|
||||
}
|
||||
// create string stream to contain header
|
||||
|
||||
+2
-2
@@ -20,7 +20,7 @@ bool complete_ROI(const ROI &roi, const DetectorGeometry &geometry) {
|
||||
|
||||
bool complete_ROI(const std::vector<ROI> &rois,
|
||||
const DetectorGeometry &geometry) {
|
||||
if (rois.empty() or rois.size() > 1) {
|
||||
if (rois.empty() || rois.size() > 1) {
|
||||
return false;
|
||||
} else {
|
||||
return complete_ROI(rois[0], geometry);
|
||||
@@ -34,7 +34,7 @@ bool complete_ROI(const ROIGeometry &roi, const DetectorGeometry &geometry) {
|
||||
|
||||
bool complete_ROI(const std::vector<ROIGeometry> &rois,
|
||||
const DetectorGeometry &geometry) {
|
||||
if (rois.empty() or rois.size() > 1) {
|
||||
if (rois.empty() || rois.size() > 1) {
|
||||
return false;
|
||||
} else {
|
||||
return complete_ROI(rois[0], geometry);
|
||||
|
||||
+1
-1
@@ -302,7 +302,7 @@ void RawFile::open_subfiles(const size_t roi_index) {
|
||||
|
||||
DetectorHeader RawFile::read_header(const std::filesystem::path &fname) {
|
||||
DetectorHeader h{};
|
||||
FILE *fp = fopen(fname.string().c_str(), "r");
|
||||
FILE *fp = fopen(fname.string().c_str(), "rb");
|
||||
if (!fp)
|
||||
throw std::runtime_error(fmt::format(
|
||||
"Could not open file '{}' for frame index 0", fname.string()));
|
||||
|
||||
+11
-11
@@ -11,8 +11,8 @@ namespace aare {
|
||||
RawFileNameComponents::RawFileNameComponents(
|
||||
const std::filesystem::path &fname) {
|
||||
m_base_path = fname.parent_path();
|
||||
m_base_name = fname.stem();
|
||||
m_ext = fname.extension();
|
||||
m_base_name = fname.stem().string();
|
||||
m_ext = fname.extension().string();
|
||||
|
||||
if (m_ext != ".json" && m_ext != ".raw") {
|
||||
throw std::runtime_error(LOCATION +
|
||||
@@ -23,7 +23,7 @@ RawFileNameComponents::RawFileNameComponents(
|
||||
try {
|
||||
auto pos = m_base_name.rfind('_');
|
||||
m_file_index = std::stoi(m_base_name.substr(pos + 1));
|
||||
} catch (const std::invalid_argument &e) {
|
||||
} catch (const std::invalid_argument &) {
|
||||
throw std::runtime_error(LOCATION + "Could not parse file index");
|
||||
}
|
||||
|
||||
@@ -370,7 +370,7 @@ void RawMasterFile::parse_json(std::istream &is) {
|
||||
|
||||
try {
|
||||
m_quad = j.at("Quad");
|
||||
} catch (const json::out_of_range &e) {
|
||||
} catch (const json::out_of_range &) {
|
||||
// keep the optional empty
|
||||
}
|
||||
// try{
|
||||
@@ -384,7 +384,7 @@ void RawMasterFile::parse_json(std::istream &is) {
|
||||
if (digital_flag) {
|
||||
m_digital_samples = j.at("Digital Samples");
|
||||
}
|
||||
} catch (const json::out_of_range &e) {
|
||||
} catch (const json::out_of_range &) {
|
||||
// keep the optional empty
|
||||
}
|
||||
try {
|
||||
@@ -393,7 +393,7 @@ void RawMasterFile::parse_json(std::istream &is) {
|
||||
if (m_transceiver_flag) {
|
||||
m_transceiver_samples = j.at("Transceiver Samples");
|
||||
}
|
||||
} catch (const json::out_of_range &e) {
|
||||
} catch (const json::out_of_range &) {
|
||||
// keep the optional empty
|
||||
}
|
||||
try {
|
||||
@@ -414,7 +414,7 @@ void RawMasterFile::parse_json(std::istream &is) {
|
||||
m_scan_parameters
|
||||
.increment_stop(); // adjust for endpoint being included
|
||||
}
|
||||
} catch (const json::out_of_range &e) {
|
||||
} catch (const json::out_of_range &) {
|
||||
// not a scan
|
||||
}
|
||||
try {
|
||||
@@ -424,7 +424,7 @@ void RawMasterFile::parse_json(std::istream &is) {
|
||||
m_udp_port_types.value().push_back(
|
||||
string_to<UDPPortPosition>(elem));
|
||||
}
|
||||
} catch (const json::out_of_range &e) {
|
||||
} catch (const json::out_of_range &) {
|
||||
// leave the optional empty
|
||||
}
|
||||
try {
|
||||
@@ -433,13 +433,13 @@ void RawMasterFile::parse_json(std::istream &is) {
|
||||
for (auto &elem : json_list_obj) {
|
||||
m_disabled_udp_ports.push_back(static_cast<size_t>(elem));
|
||||
}
|
||||
} catch (const json::out_of_range &e) {
|
||||
} catch (const json::out_of_range &) {
|
||||
m_disabled_udp_ports
|
||||
.clear(); // empty list if not present in master file
|
||||
}
|
||||
try {
|
||||
m_udp_interfaces_per_module = {j.at("Number of UDP Interfaces"), 1};
|
||||
} catch (const json::out_of_range &e) {
|
||||
} catch (const json::out_of_range &) {
|
||||
if (m_type == DetectorType::Eiger && m_quad == 1)
|
||||
m_udp_interfaces_per_module = {2, 1};
|
||||
else if (m_type == DetectorType::Eiger) {
|
||||
@@ -485,7 +485,7 @@ void RawMasterFile::parse_json(std::istream &is) {
|
||||
}
|
||||
}
|
||||
|
||||
} catch (const json::out_of_range &e) {
|
||||
} catch (const json::out_of_range &) {
|
||||
// fill ROI with full detector size if not present in master file
|
||||
m_rois.push_back(
|
||||
{0, m_detector_layout.col * static_cast<ssize_t>(m_pixels_x), 0,
|
||||
|
||||
+1
-1
@@ -163,7 +163,7 @@ void RawSubFile::parse_fname(const std::filesystem::path &fname) {
|
||||
// f1 is the file index - thi is the one we need
|
||||
// 0 is the measurement index, will not change
|
||||
m_path = fname.parent_path();
|
||||
m_base_name = fname.filename();
|
||||
m_base_name = fname.filename().string();
|
||||
|
||||
// Regex to extract numbers after 'd' and 'f'
|
||||
std::regex pattern(R"(^(.*_d)(\d+)(_f)(\d+)(_\d+\.raw)$)");
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <aare/algorithm.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
using aare::ssize_t;
|
||||
|
||||
TEST_CASE("Find the closed index in a 1D array", "[algorithm]") {
|
||||
aare::NDArray<double, 1> arr({5});
|
||||
for (ssize_t i = 0; i < arr.size(); i++) {
|
||||
|
||||
+3
-2
@@ -10,6 +10,7 @@ using Catch::Matchers::WithinAbs;
|
||||
#include <vector>
|
||||
|
||||
using aare::BitOffset;
|
||||
using aare::ssize_t;
|
||||
|
||||
TEST_CASE("test_adc_sar_05_decode64to16") {
|
||||
uint64_t input = 0;
|
||||
@@ -24,7 +25,7 @@ TEST_CASE("test_adc_sar_05_decode64to16") {
|
||||
// test all bits by iteratting through the bitlist
|
||||
std::vector<int> bitlist = {29, 19, 28, 18, 31, 21, 27, 20, 24, 23, 25, 22};
|
||||
for (size_t i = 0; i < bitlist.size(); i++) {
|
||||
input = 1UL << bitlist[i];
|
||||
input = 1ULL << bitlist[i];
|
||||
output = aare::adc_sar_05_decode64to16(input);
|
||||
CHECK(output == (1 << i));
|
||||
}
|
||||
@@ -94,7 +95,7 @@ TEST_CASE("Each byte buffer decoder maps to its own bit order") {
|
||||
};
|
||||
|
||||
for (const auto &c : cases) {
|
||||
uint64_t word = (1UL << c.bit0) | (1UL << c.bit1);
|
||||
uint64_t word = (1ULL << c.bit0) | (1ULL << c.bit1);
|
||||
std::vector<uint8_t> buffer(8);
|
||||
std::memcpy(buffer.data(), &word, sizeof(word));
|
||||
aare::NDView<const uint8_t, 2> bytes(buffer.data(), {1, 8});
|
||||
|
||||
+4
-1
@@ -269,7 +269,10 @@ void fit_3d(const FitModel<Model> &model, NDView<double, 1> x,
|
||||
NDView<double, 3> par_out, NDView<double, 3> err_out,
|
||||
NDView<double, 2> chi2_out, int n_threads,
|
||||
std::optional<const NDView<size_t, 3>> fit_range) {
|
||||
constexpr std::size_t npar = Model::npar;
|
||||
|
||||
// static so the lambda below can use it as an array size without
|
||||
// capturing it, which MSVC otherwise rejects
|
||||
static constexpr std::size_t npar = Model::npar;
|
||||
detail::check_fit_3d_shapes<Model>(x, y, y_err, par_out, err_out, chi2_out);
|
||||
|
||||
const bool has_errors = (y_err.size() > 0);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
using aare::Minimizer;
|
||||
using aare::NDArray;
|
||||
using aare::NDView;
|
||||
using aare::ssize_t;
|
||||
using Catch::Approx;
|
||||
|
||||
namespace {
|
||||
@@ -1099,7 +1100,7 @@ TEST_CASE("Samples with a zero error are ignored even when NaN", "[fit]") {
|
||||
INFO("minimizer " << name(minimizer));
|
||||
const double nan = std::numeric_limits<double>::quiet_NaN();
|
||||
|
||||
constexpr ssize_t n = 10;
|
||||
static constexpr ssize_t n = 10; // static: used inside GENERATE's lambda
|
||||
NDArray<double, 1> x({n});
|
||||
NDArray<double, 1> y({n});
|
||||
NDArray<double, 1> y_err({n}, 1.0);
|
||||
|
||||
@@ -20,6 +20,7 @@ using aare::FileConfig;
|
||||
using aare::Frame;
|
||||
using aare::NumpyFile;
|
||||
using aare::PedestalTrackingPixelHistogram;
|
||||
using aare::ssize_t;
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
using aare::NDArray;
|
||||
using aare::NDView;
|
||||
using aare::PixelHistogram;
|
||||
using aare::ssize_t;
|
||||
|
||||
namespace {
|
||||
// The synchronous fill() has been removed; fill_async() is the only entry
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
#include "aare/logger.hpp"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
using Catch::Matchers::EndsWith;
|
||||
using Catch::Matchers::Matches;
|
||||
using Catch::Matchers::StartsWith;
|
||||
|
||||
TEST_CASE("Log timestamp is HH:MM:SS.mmm", "[logger]") {
|
||||
const std::string ts = aare::Logger::Timestamp();
|
||||
REQUIRE_THAT(ts, Matches(R"(\d{2}:\d{2}:\d{2}\.\d{3})"));
|
||||
}
|
||||
|
||||
TEST_CASE("short_file_name strips both kinds of directory separators",
|
||||
"[logger]") {
|
||||
REQUIRE(std::string(aare::short_file_name("/a/b/File.cpp")) == "File.cpp");
|
||||
REQUIRE(std::string(aare::short_file_name("C:\\a\\b\\File.cpp")) ==
|
||||
"File.cpp");
|
||||
REQUIRE(std::string(aare::short_file_name("File.cpp")) == "File.cpp");
|
||||
}
|
||||
|
||||
TEST_CASE("LOG writes one coloured line with timestamp and level", "[logger]") {
|
||||
std::ostringstream captured;
|
||||
auto *previous = std::clog.rdbuf(captured.rdbuf());
|
||||
LOG(aare::logWARNING) << "hello " << 42;
|
||||
std::clog.rdbuf(previous);
|
||||
|
||||
const std::string line = captured.str();
|
||||
// <colour>- HH:MM:SS.mmm WARNING: hello 42<reset>\n
|
||||
REQUIRE_THAT(line, StartsWith(std::string(YELLOW BOLD) + "- "));
|
||||
REQUIRE_THAT(line, Matches(std::string("\x1b\\[33m\x1b\\[1m- ") +
|
||||
R"(\d{2}:\d{2}:\d{2}\.\d{3} WARNING: hello 42)" +
|
||||
"\x1b\\[0m\n"));
|
||||
REQUIRE_THAT(line, EndsWith(std::string(RESET) + "\n"));
|
||||
}
|
||||
Reference in new issue
Block a user