mirror of
https://github.com/slsdetectorgroup/aare.git
synced 2025-12-15 17:41:25 +01:00
Compare commits
25 Commits
dev/highz/
...
fix/spsc-m
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e412e72e5b | ||
|
|
9008393955 | ||
| 74280379ce | |||
| 474c35cc6b | |||
| e2a97d3c45 | |||
|
|
a8b87e6b53 | ||
| 12114e7275 | |||
| 7926993bb2 | |||
| ed7fb1f1f9 | |||
|
|
8ab98b356b | ||
| d908ad3636 | |||
| 8733a1d66f | |||
| 437f7cec89 | |||
|
|
6c3524298f | ||
| b59277c4bf | |||
| cb163c79b4 | |||
|
|
a0fb4900f0 | ||
|
|
91d74110fa | ||
| f54e76e6bf | |||
|
|
c6da36d10b | ||
|
|
9a3694b980 | ||
|
|
85c3bf7bed | ||
|
|
8eb7fec435 | ||
|
|
83717571c8 | ||
|
|
5a9c3b717e |
12
RELEASE.md
12
RELEASE.md
@@ -1,16 +1,22 @@
|
||||
# Release notes
|
||||
|
||||
|
||||
### head
|
||||
### 2025.8.22
|
||||
|
||||
Features:
|
||||
|
||||
- Apply calibration works in G0 if passes a 2D calibration and pedestal
|
||||
- count pixels that switch
|
||||
- calculate pedestal (also g0 version)
|
||||
- NDArray::view() needs an lvalue to reduce issues with the view outliving the array
|
||||
|
||||
|
||||
### 2025.07.18
|
||||
Bugfixes:
|
||||
|
||||
- Now using glibc 2.17 in conda builds (was using the host)
|
||||
- Fixed shifted pixels in clusters close to the edge of a frame
|
||||
|
||||
### 2025.7.18
|
||||
|
||||
Features:
|
||||
|
||||
@@ -24,7 +30,7 @@ Bugfixes:
|
||||
- Removed unused file: ClusterFile.cpp
|
||||
|
||||
|
||||
### 2025.05.22
|
||||
### 2025.5.22
|
||||
|
||||
Features:
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ FetchContent_MakeAvailable(benchmark)
|
||||
|
||||
add_executable(benchmarks)
|
||||
|
||||
target_sources(benchmarks PRIVATE ndarray_benchmark.cpp calculateeta_benchmark.cpp)
|
||||
target_sources(benchmarks PRIVATE ndarray_benchmark.cpp calculateeta_benchmark.cpp reduce_benchmark.cpp)
|
||||
|
||||
# Link Google Benchmark and other necessary libraries
|
||||
target_link_libraries(benchmarks PRIVATE benchmark::benchmark aare_core aare_compiler_flags)
|
||||
|
||||
168
benchmarks/reduce_benchmark.cpp
Normal file
168
benchmarks/reduce_benchmark.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
#include "aare/Cluster.hpp"
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
using namespace aare;
|
||||
|
||||
class ClustersForReduceFixture : public benchmark::Fixture {
|
||||
public:
|
||||
Cluster<int, 5, 5> cluster_5x5{};
|
||||
Cluster<int, 3, 3> cluster_3x3{};
|
||||
|
||||
private:
|
||||
using benchmark::Fixture::SetUp;
|
||||
|
||||
void SetUp([[maybe_unused]] const benchmark::State &state) override {
|
||||
int temp_data[25] = {1, 1, 1, 1, 1, 1, 1, 2, 1, 1,
|
||||
1, 2, 3, 1, 2, 1, 1, 1, 1, 2};
|
||||
std::copy(std::begin(temp_data), std::end(temp_data),
|
||||
std::begin(cluster_5x5.data));
|
||||
|
||||
cluster_5x5.x = 5;
|
||||
cluster_5x5.y = 5;
|
||||
|
||||
int temp_data2[9] = {1, 1, 1, 2, 3, 1, 2, 2, 1};
|
||||
std::copy(std::begin(temp_data2), std::end(temp_data2),
|
||||
std::begin(cluster_3x3.data));
|
||||
|
||||
cluster_3x3.x = 5;
|
||||
cluster_3x3.y = 5;
|
||||
}
|
||||
|
||||
// void TearDown(::benchmark::State& state) {
|
||||
// }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
Cluster<T, 3, 3, int16_t> reduce_to_3x3(const Cluster<T, 5, 5, int16_t> &c) {
|
||||
Cluster<T, 3, 3, int16_t> result;
|
||||
|
||||
// Write out the sums in the hope that the compiler can optimize this
|
||||
std::array<T, 9> sum_3x3_subclusters;
|
||||
|
||||
// Write out the sums in the hope that the compiler can optimize this
|
||||
sum_3x3_subclusters[0] = c.data[0] + c.data[1] + c.data[2] + c.data[5] +
|
||||
c.data[6] + c.data[7] + c.data[10] + c.data[11] +
|
||||
c.data[12];
|
||||
sum_3x3_subclusters[1] = c.data[1] + c.data[2] + c.data[3] + c.data[6] +
|
||||
c.data[7] + c.data[8] + c.data[11] + c.data[12] +
|
||||
c.data[13];
|
||||
sum_3x3_subclusters[2] = c.data[2] + c.data[3] + c.data[4] + c.data[7] +
|
||||
c.data[8] + c.data[9] + c.data[12] + c.data[13] +
|
||||
c.data[14];
|
||||
sum_3x3_subclusters[3] = c.data[5] + c.data[6] + c.data[7] + c.data[10] +
|
||||
c.data[11] + c.data[12] + c.data[15] + c.data[16] +
|
||||
c.data[17];
|
||||
sum_3x3_subclusters[4] = c.data[6] + c.data[7] + c.data[8] + c.data[11] +
|
||||
c.data[12] + c.data[13] + c.data[16] + c.data[17] +
|
||||
c.data[18];
|
||||
sum_3x3_subclusters[5] = c.data[7] + c.data[8] + c.data[9] + c.data[12] +
|
||||
c.data[13] + c.data[14] + c.data[17] + c.data[18] +
|
||||
c.data[19];
|
||||
sum_3x3_subclusters[6] = c.data[10] + c.data[11] + c.data[12] + c.data[15] +
|
||||
c.data[16] + c.data[17] + c.data[20] + c.data[21] +
|
||||
c.data[22];
|
||||
sum_3x3_subclusters[7] = c.data[11] + c.data[12] + c.data[13] + c.data[16] +
|
||||
c.data[17] + c.data[18] + c.data[21] + c.data[22] +
|
||||
c.data[23];
|
||||
sum_3x3_subclusters[8] = c.data[12] + c.data[13] + c.data[14] + c.data[17] +
|
||||
c.data[18] + c.data[19] + c.data[22] + c.data[23] +
|
||||
c.data[24];
|
||||
|
||||
auto index = std::max_element(sum_3x3_subclusters.begin(),
|
||||
sum_3x3_subclusters.end()) -
|
||||
sum_3x3_subclusters.begin();
|
||||
|
||||
switch (index) {
|
||||
case 0:
|
||||
result.x = c.x - 1;
|
||||
result.y = c.y + 1;
|
||||
result.data = {c.data[0], c.data[1], c.data[2], c.data[5], c.data[6],
|
||||
c.data[7], c.data[10], c.data[11], c.data[12]};
|
||||
break;
|
||||
case 1:
|
||||
result.x = c.x;
|
||||
result.y = c.y + 1;
|
||||
result.data = {c.data[1], c.data[2], c.data[3], c.data[6], c.data[7],
|
||||
c.data[8], c.data[11], c.data[12], c.data[13]};
|
||||
break;
|
||||
case 2:
|
||||
result.x = c.x + 1;
|
||||
result.y = c.y + 1;
|
||||
result.data = {c.data[2], c.data[3], c.data[4], c.data[7], c.data[8],
|
||||
c.data[9], c.data[12], c.data[13], c.data[14]};
|
||||
break;
|
||||
case 3:
|
||||
result.x = c.x - 1;
|
||||
result.y = c.y;
|
||||
result.data = {c.data[5], c.data[6], c.data[7],
|
||||
c.data[10], c.data[11], c.data[12],
|
||||
c.data[15], c.data[16], c.data[17]};
|
||||
break;
|
||||
case 4:
|
||||
result.x = c.x + 1;
|
||||
result.y = c.y;
|
||||
result.data = {c.data[6], c.data[7], c.data[8],
|
||||
c.data[11], c.data[12], c.data[13],
|
||||
c.data[16], c.data[17], c.data[18]};
|
||||
break;
|
||||
case 5:
|
||||
result.x = c.x + 1;
|
||||
result.y = c.y;
|
||||
result.data = {c.data[7], c.data[8], c.data[9],
|
||||
c.data[12], c.data[13], c.data[14],
|
||||
c.data[17], c.data[18], c.data[19]};
|
||||
break;
|
||||
case 6:
|
||||
result.x = c.x + 1;
|
||||
result.y = c.y - 1;
|
||||
result.data = {c.data[10], c.data[11], c.data[12],
|
||||
c.data[15], c.data[16], c.data[17],
|
||||
c.data[20], c.data[21], c.data[22]};
|
||||
break;
|
||||
case 7:
|
||||
result.x = c.x + 1;
|
||||
result.y = c.y - 1;
|
||||
result.data = {c.data[11], c.data[12], c.data[13],
|
||||
c.data[16], c.data[17], c.data[18],
|
||||
c.data[21], c.data[22], c.data[23]};
|
||||
break;
|
||||
case 8:
|
||||
result.x = c.x + 1;
|
||||
result.y = c.y - 1;
|
||||
result.data = {c.data[12], c.data[13], c.data[14],
|
||||
c.data[17], c.data[18], c.data[19],
|
||||
c.data[22], c.data[23], c.data[24]};
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
BENCHMARK_F(ClustersForReduceFixture, Reduce2x2)(benchmark::State &st) {
|
||||
for (auto _ : st) {
|
||||
// This code gets timed
|
||||
benchmark::DoNotOptimize(reduce_to_2x2<int, 3, 3, int16_t>(
|
||||
cluster_3x3)); // make sure compiler evaluates the expression
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_F(ClustersForReduceFixture, SpecificReduce2x2)(benchmark::State &st) {
|
||||
for (auto _ : st) {
|
||||
// This code gets timed
|
||||
benchmark::DoNotOptimize(reduce_to_2x2<int>(cluster_3x3));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_F(ClustersForReduceFixture, Reduce3x3)(benchmark::State &st) {
|
||||
for (auto _ : st) {
|
||||
// This code gets timed
|
||||
benchmark::DoNotOptimize(
|
||||
reduce_to_3x3<int, 5, 5, int16_t>(cluster_5x5));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_F(ClustersForReduceFixture, SpecificReduce3x3)(benchmark::State &st) {
|
||||
for (auto _ : st) {
|
||||
// This code gets timed
|
||||
benchmark::DoNotOptimize(reduce_to_3x3<int>(cluster_5x5));
|
||||
}
|
||||
}
|
||||
@@ -3,3 +3,14 @@ python:
|
||||
- 3.12
|
||||
- 3.13
|
||||
|
||||
c_compiler:
|
||||
- gcc # [linux]
|
||||
|
||||
c_stdlib:
|
||||
- sysroot # [linux]
|
||||
|
||||
cxx_compiler:
|
||||
- gxx # [linux]
|
||||
|
||||
c_stdlib_version: # [linux]
|
||||
- 2.17 # [linux]
|
||||
|
||||
@@ -16,6 +16,8 @@ build:
|
||||
|
||||
requirements:
|
||||
build:
|
||||
- {{ compiler('c') }}
|
||||
- {{ stdlib("c") }}
|
||||
- {{ compiler('cxx') }}
|
||||
- cmake
|
||||
- ninja
|
||||
|
||||
@@ -12,4 +12,11 @@ ClusterVector
|
||||
:members:
|
||||
:undoc-members:
|
||||
:private-members:
|
||||
|
||||
|
||||
**Free Functions:**
|
||||
|
||||
.. doxygenfunction:: aare::reduce_to_3x3(const ClusterVector<Cluster<T, ClusterSizeX, ClusterSizeY, CoordType>>&)
|
||||
|
||||
.. doxygenfunction:: aare::reduce_to_2x2(const ClusterVector<Cluster<T, ClusterSizeX, ClusterSizeY, CoordType>>&)
|
||||
|
||||
@@ -33,4 +33,17 @@ C++ functions that support the ClusterVector or to view it as a numpy array.
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
:inherited-members:
|
||||
:inherited-members:
|
||||
|
||||
|
||||
**Free Functions:**
|
||||
|
||||
.. autofunction:: reduce_to_3x3
|
||||
:noindex:
|
||||
|
||||
Reduce a single Cluster to 3x3 by taking the 3x3 subcluster with highest photon energy.
|
||||
|
||||
.. autofunction:: reduce_to_2x2
|
||||
:noindex:
|
||||
|
||||
Reduce a single Cluster to 2x2 by taking the 2x2 subcluster with highest photon energy.
|
||||
|
||||
@@ -28,7 +28,7 @@ enum class pixel : int {
|
||||
template <typename T> struct Eta2 {
|
||||
double x;
|
||||
double y;
|
||||
int c;
|
||||
int c{0};
|
||||
T sum;
|
||||
};
|
||||
|
||||
@@ -70,6 +70,8 @@ calculate_eta2(const Cluster<T, ClusterSizeX, ClusterSizeY, CoordType> &cl) {
|
||||
size_t index_bottom_left_max_2x2_subcluster =
|
||||
(int(c / (ClusterSizeX - 1))) * ClusterSizeX + c % (ClusterSizeX - 1);
|
||||
|
||||
// calculate direction of gradient
|
||||
|
||||
// check that cluster center is in max subcluster
|
||||
if (cluster_center_index != index_bottom_left_max_2x2_subcluster &&
|
||||
cluster_center_index != index_bottom_left_max_2x2_subcluster + 1 &&
|
||||
@@ -128,12 +130,15 @@ Eta2<T> calculate_eta2(const Cluster<T, 2, 2, int16_t> &cl) {
|
||||
Eta2<T> eta{};
|
||||
|
||||
if ((cl.data[0] + cl.data[1]) != 0)
|
||||
eta.x = static_cast<double>(cl.data[1]) / (cl.data[0] + cl.data[1]);
|
||||
eta.x = static_cast<double>(cl.data[1]) /
|
||||
(cl.data[0] + cl.data[1]); // between (0,1) the closer to zero
|
||||
// left value probably larger
|
||||
if ((cl.data[0] + cl.data[2]) != 0)
|
||||
eta.y = static_cast<double>(cl.data[2]) / (cl.data[0] + cl.data[2]);
|
||||
eta.y = static_cast<double>(cl.data[2]) /
|
||||
(cl.data[0] + cl.data[2]); // between (0,1) the closer to zero
|
||||
// bottom value probably larger
|
||||
eta.sum = cl.sum();
|
||||
eta.c = static_cast<int>(corner::cBottomLeft); // TODO! This is not correct,
|
||||
// but need to put something
|
||||
|
||||
return eta;
|
||||
}
|
||||
|
||||
@@ -150,13 +155,11 @@ template <typename T> Eta2<T> calculate_eta3(const Cluster<T, 3, 3> &cl) {
|
||||
|
||||
eta.sum = sum;
|
||||
|
||||
eta.c = corner::cBottomLeft;
|
||||
|
||||
if ((cl.data[3] + cl.data[4] + cl.data[5]) != 0)
|
||||
|
||||
eta.x = static_cast<double>(-cl.data[3] + cl.data[3 + 2]) /
|
||||
|
||||
(cl.data[3] + cl.data[4] + cl.data[5]);
|
||||
(cl.data[3] + cl.data[4] + cl.data[5]); // (-1,1)
|
||||
|
||||
if ((cl.data[1] + cl.data[4] + cl.data[7]) != 0)
|
||||
|
||||
|
||||
158
include/aare/Cluster.hpp
Normal file → Executable file
158
include/aare/Cluster.hpp
Normal file → Executable file
@@ -8,6 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "logger.hpp"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
@@ -74,6 +75,163 @@ struct Cluster {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Reduce a cluster to a 2x2 cluster by selecting the 2x2 block with the
|
||||
* highest sum.
|
||||
* @param c Cluster to reduce
|
||||
* @return reduced cluster
|
||||
*/
|
||||
template <typename T, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
|
||||
typename CoordType = int16_t>
|
||||
Cluster<T, 2, 2, CoordType>
|
||||
reduce_to_2x2(const Cluster<T, ClusterSizeX, ClusterSizeY, CoordType> &c) {
|
||||
|
||||
static_assert(ClusterSizeX >= 2 && ClusterSizeY >= 2,
|
||||
"Cluster sizes must be at least 2x2 for reduction to 2x2");
|
||||
|
||||
// TODO maybe add sanity check and check that center is in max subcluster
|
||||
Cluster<T, 2, 2, CoordType> result;
|
||||
|
||||
auto [sum, index] = c.max_sum_2x2();
|
||||
|
||||
int16_t cluster_center_index =
|
||||
(ClusterSizeX / 2) + (ClusterSizeY / 2) * ClusterSizeX;
|
||||
|
||||
int16_t index_bottom_left_max_2x2_subcluster =
|
||||
(int(index / (ClusterSizeX - 1))) * ClusterSizeX +
|
||||
index % (ClusterSizeX - 1);
|
||||
|
||||
result.x =
|
||||
c.x + (index_bottom_left_max_2x2_subcluster - cluster_center_index) %
|
||||
ClusterSizeX;
|
||||
|
||||
result.y =
|
||||
c.y - (index_bottom_left_max_2x2_subcluster - cluster_center_index) /
|
||||
ClusterSizeX;
|
||||
result.data = {
|
||||
c.data[index_bottom_left_max_2x2_subcluster],
|
||||
c.data[index_bottom_left_max_2x2_subcluster + 1],
|
||||
c.data[index_bottom_left_max_2x2_subcluster + ClusterSizeX],
|
||||
c.data[index_bottom_left_max_2x2_subcluster + ClusterSizeX + 1]};
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Cluster<T, 2, 2, int16_t> reduce_to_2x2(const Cluster<T, 3, 3, int16_t> &c) {
|
||||
Cluster<T, 2, 2, int16_t> result;
|
||||
|
||||
auto [s, i] = c.max_sum_2x2();
|
||||
switch (i) {
|
||||
case 0:
|
||||
result.x = c.x - 1;
|
||||
result.y = c.y + 1;
|
||||
result.data = {c.data[0], c.data[1], c.data[3], c.data[4]};
|
||||
break;
|
||||
case 1:
|
||||
result.x = c.x;
|
||||
result.y = c.y + 1;
|
||||
result.data = {c.data[1], c.data[2], c.data[4], c.data[5]};
|
||||
break;
|
||||
case 2:
|
||||
result.x = c.x - 1;
|
||||
result.y = c.y;
|
||||
result.data = {c.data[3], c.data[4], c.data[6], c.data[7]};
|
||||
break;
|
||||
case 3:
|
||||
result.x = c.x;
|
||||
result.y = c.y;
|
||||
result.data = {c.data[4], c.data[5], c.data[7], c.data[8]};
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
|
||||
typename CoordType = int16_t>
|
||||
inline std::pair<T, uint16_t>
|
||||
max_3x3_sum(const Cluster<T, ClusterSizeX, ClusterSizeY, CoordType> &cluster) {
|
||||
|
||||
if constexpr (ClusterSizeX == 3 && ClusterSizeY == 3) {
|
||||
return std::make_pair(cluster.sum(), 0);
|
||||
} else {
|
||||
|
||||
size_t index = 0;
|
||||
T max_3x3_subcluster_sum = 0;
|
||||
for (size_t i = 0; i < ClusterSizeY - 2; ++i) {
|
||||
for (size_t j = 0; j < ClusterSizeX - 2; ++j) {
|
||||
|
||||
T sum = cluster.data[i * ClusterSizeX + j] +
|
||||
cluster.data[i * ClusterSizeX + j + 1] +
|
||||
cluster.data[i * ClusterSizeX + j + 2] +
|
||||
cluster.data[(i + 1) * ClusterSizeX + j] +
|
||||
cluster.data[(i + 1) * ClusterSizeX + j + 1] +
|
||||
cluster.data[(i + 1) * ClusterSizeX + j + 2] +
|
||||
cluster.data[(i + 2) * ClusterSizeX + j] +
|
||||
cluster.data[(i + 2) * ClusterSizeX + j + 1] +
|
||||
cluster.data[(i + 2) * ClusterSizeX + j + 2];
|
||||
if (sum > max_3x3_subcluster_sum) {
|
||||
max_3x3_subcluster_sum = sum;
|
||||
index = i * (ClusterSizeX - 2) + j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair(max_3x3_subcluster_sum, index);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reduce a cluster to a 3x3 cluster by selecting the 3x3 block with the
|
||||
* highest sum.
|
||||
* @param c Cluster to reduce
|
||||
* @return reduced cluster
|
||||
*/
|
||||
template <typename T, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
|
||||
typename CoordType = int16_t>
|
||||
Cluster<T, 3, 3, CoordType>
|
||||
reduce_to_3x3(const Cluster<T, ClusterSizeX, ClusterSizeY, CoordType> &c) {
|
||||
|
||||
static_assert(ClusterSizeX >= 3 && ClusterSizeY >= 3,
|
||||
"Cluster sizes must be at least 3x3 for reduction to 3x3");
|
||||
|
||||
Cluster<T, 3, 3, CoordType> result;
|
||||
|
||||
// TODO maybe add sanity check and check that center is in max subcluster
|
||||
|
||||
auto [sum, index] = max_3x3_sum(c);
|
||||
|
||||
int16_t cluster_center_index =
|
||||
(ClusterSizeX / 2) + (ClusterSizeY / 2) * ClusterSizeX;
|
||||
|
||||
int16_t index_center_max_3x3_subcluster =
|
||||
(int(index / (ClusterSizeX - 2))) * ClusterSizeX + ClusterSizeX +
|
||||
index % (ClusterSizeX - 2) + 1;
|
||||
|
||||
int16_t index_3x3_subcluster_cluster_center =
|
||||
int((cluster_center_index - 1 - ClusterSizeX) / ClusterSizeX) *
|
||||
(ClusterSizeX - 2) +
|
||||
(cluster_center_index - 1 - ClusterSizeX) % ClusterSizeX;
|
||||
|
||||
result.x =
|
||||
c.x + (index % (ClusterSizeX - 2) -
|
||||
(index_3x3_subcluster_cluster_center % (ClusterSizeX - 2)));
|
||||
result.y =
|
||||
c.y - (index / (ClusterSizeX - 2) -
|
||||
(index_3x3_subcluster_cluster_center / (ClusterSizeX - 2)));
|
||||
|
||||
result.data = {c.data[index_center_max_3x3_subcluster - ClusterSizeX - 1],
|
||||
c.data[index_center_max_3x3_subcluster - ClusterSizeX],
|
||||
c.data[index_center_max_3x3_subcluster - ClusterSizeX + 1],
|
||||
c.data[index_center_max_3x3_subcluster - 1],
|
||||
c.data[index_center_max_3x3_subcluster],
|
||||
c.data[index_center_max_3x3_subcluster + 1],
|
||||
c.data[index_center_max_3x3_subcluster + ClusterSizeX - 1],
|
||||
c.data[index_center_max_3x3_subcluster + ClusterSizeX],
|
||||
c.data[index_center_max_3x3_subcluster + ClusterSizeX + 1]};
|
||||
return result;
|
||||
}
|
||||
|
||||
// Type Traits for is_cluster_type
|
||||
template <typename T>
|
||||
struct is_cluster : std::false_type {}; // Default case: Not a Cluster
|
||||
|
||||
@@ -19,11 +19,9 @@ class ClusterFinder {
|
||||
const PEDESTAL_TYPE c3;
|
||||
Pedestal<PEDESTAL_TYPE> m_pedestal;
|
||||
ClusterVector<ClusterType> m_clusters;
|
||||
const uint32_t ClusterSizeX;
|
||||
const uint32_t ClusterSizeY;
|
||||
|
||||
static const uint8_t SavedClusterSizeX = ClusterType::cluster_size_x;
|
||||
static const uint8_t SavedClusterSizeY = ClusterType::cluster_size_y;
|
||||
static const uint8_t ClusterSizeX = ClusterType::cluster_size_x;
|
||||
static const uint8_t ClusterSizeY = ClusterType::cluster_size_y;
|
||||
using CT = typename ClusterType::value_type;
|
||||
|
||||
public:
|
||||
@@ -36,12 +34,10 @@ class ClusterFinder {
|
||||
*
|
||||
*/
|
||||
ClusterFinder(Shape<2> image_size, PEDESTAL_TYPE nSigma = 5.0,
|
||||
size_t capacity = 1000000,
|
||||
uint32_t cluster_size_x = 3, uint32_t cluster_size_y = 3)
|
||||
size_t capacity = 1000000)
|
||||
: m_image_size(image_size), m_nSigma(nSigma),
|
||||
c2(sqrt((cluster_size_y + 1) / 2 * (cluster_size_x + 1) / 2)),
|
||||
c3(sqrt(cluster_size_x * cluster_size_y)),
|
||||
ClusterSizeX(cluster_size_x), ClusterSizeY(cluster_size_y),
|
||||
c2(sqrt((ClusterSizeY + 1) / 2 * (ClusterSizeX + 1) / 2)),
|
||||
c3(sqrt(ClusterSizeX * ClusterSizeY)),
|
||||
m_pedestal(image_size[0], image_size[1]), m_clusters(capacity) {
|
||||
LOG(logDEBUG) << "ClusterFinder: "
|
||||
<< "image_size: " << image_size[0] << "x" << image_size[1]
|
||||
@@ -78,9 +74,6 @@ class ClusterFinder {
|
||||
// // 4,4 -> +/- 2
|
||||
int dy = ClusterSizeY / 2;
|
||||
int dx = ClusterSizeX / 2;
|
||||
int dy2 = SavedClusterSizeY / 2;
|
||||
int dx2 = SavedClusterSizeX / 2;
|
||||
|
||||
int has_center_pixel_x =
|
||||
ClusterSizeX %
|
||||
2; // for even sized clusters there is no proper cluster center and
|
||||
@@ -142,14 +135,16 @@ class ClusterFinder {
|
||||
// It's worth redoing the look since most of the time we
|
||||
// don't have a photon
|
||||
int i = 0;
|
||||
for (int ir = -dy2; ir < dy2 + has_center_pixel_y; ir++) {
|
||||
for (int ic = -dx2; ic < dx2 + has_center_pixel_y; ic++) {
|
||||
for (int ir = -dy; ir < dy + has_center_pixel_y; ir++) {
|
||||
for (int ic = -dx; ic < dx + has_center_pixel_y; ic++) {
|
||||
if (ix + ic >= 0 && ix + ic < frame.shape(1) &&
|
||||
iy + ir >= 0 && iy + ir < frame.shape(0)) {
|
||||
|
||||
CT tmp = static_cast<CT>(frame(iy + ir, ix + ic)) - static_cast<CT>(m_pedestal.mean(iy + ir, ix + ic));
|
||||
cluster.data[i] = tmp; // Watch for out of bounds access
|
||||
|
||||
CT tmp =
|
||||
static_cast<CT>(frame(iy + ir, ix + ic)) -
|
||||
static_cast<CT>(
|
||||
m_pedestal.mean(iy + ir, ix + ic));
|
||||
cluster.data[i] =
|
||||
tmp; // Watch for out of bounds access
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
@@ -121,8 +121,7 @@ class ClusterFinderMT {
|
||||
* @param n_threads number of threads to use
|
||||
*/
|
||||
ClusterFinderMT(Shape<2> image_size, PEDESTAL_TYPE nSigma = 5.0,
|
||||
size_t capacity = 2000, size_t n_threads = 3,
|
||||
uint32_t cluster_size_x = 3, uint32_t cluster_size_y = 3)
|
||||
size_t capacity = 2000, size_t n_threads = 3)
|
||||
: m_n_threads(n_threads) {
|
||||
|
||||
LOG(logDEBUG1) << "ClusterFinderMT: "
|
||||
@@ -135,7 +134,7 @@ class ClusterFinderMT {
|
||||
m_cluster_finders.push_back(
|
||||
std::make_unique<
|
||||
ClusterFinder<ClusterType, FRAME_TYPE, PEDESTAL_TYPE>>(
|
||||
image_size, nSigma, capacity, cluster_size_x, cluster_size_y));
|
||||
image_size, nSigma, capacity));
|
||||
}
|
||||
for (size_t i = 0; i < n_threads; i++) {
|
||||
m_input_queues.emplace_back(std::make_unique<InputQueue>(200));
|
||||
|
||||
@@ -32,8 +32,7 @@ class ClusterVector; // Forward declaration
|
||||
*/
|
||||
template <typename T, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
|
||||
typename CoordType>
|
||||
class ClusterVector<Cluster<T, ClusterSizeX, ClusterSizeY, CoordType>>
|
||||
{
|
||||
class ClusterVector<Cluster<T, ClusterSizeX, ClusterSizeY, CoordType>> {
|
||||
|
||||
std::vector<Cluster<T, ClusterSizeX, ClusterSizeY, CoordType>> m_data{};
|
||||
int32_t m_frame_number{0}; // TODO! Check frame number size and type
|
||||
@@ -173,4 +172,40 @@ class ClusterVector<Cluster<T, ClusterSizeX, ClusterSizeY, CoordType>>
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Reduce a cluster to a 2x2 cluster by selecting the 2x2 block with the
|
||||
* highest sum.
|
||||
* @param cv Clustervector containing clusters to reduce
|
||||
* @return Clustervector with reduced clusters
|
||||
*/
|
||||
template <typename T, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
|
||||
typename CoordType = uint16_t>
|
||||
ClusterVector<Cluster<T, 2, 2, CoordType>> reduce_to_2x2(
|
||||
const ClusterVector<Cluster<T, ClusterSizeX, ClusterSizeY, CoordType>>
|
||||
&cv) {
|
||||
ClusterVector<Cluster<T, 2, 2, CoordType>> result;
|
||||
for (const auto &c : cv) {
|
||||
result.push_back(reduce_to_2x2(c));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reduce a cluster to a 3x3 cluster by selecting the 3x3 block with the
|
||||
* highest sum.
|
||||
* @param cv Clustervector containing clusters to reduce
|
||||
* @return Clustervector with reduced clusters
|
||||
*/
|
||||
template <typename T, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
|
||||
typename CoordType = uint16_t>
|
||||
ClusterVector<Cluster<T, 3, 3, CoordType>> reduce_to_3x3(
|
||||
const ClusterVector<Cluster<T, ClusterSizeX, ClusterSizeY, CoordType>>
|
||||
&cv) {
|
||||
ClusterVector<Cluster<T, 3, 3, CoordType>> result;
|
||||
for (const auto &c : cv) {
|
||||
result.push_back(reduce_to_3x3(c));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace aare
|
||||
@@ -105,7 +105,7 @@ class Frame {
|
||||
* @tparam T type of the pixels
|
||||
* @return NDView<T, 2>
|
||||
*/
|
||||
template <typename T> NDView<T, 2> view() {
|
||||
template <typename T> NDView<T, 2> view() & {
|
||||
std::array<ssize_t, 2> shape = {static_cast<ssize_t>(m_rows),
|
||||
static_cast<ssize_t>(m_cols)};
|
||||
T *data = reinterpret_cast<T *>(m_data);
|
||||
|
||||
@@ -45,19 +45,63 @@ template <class T> struct ProducerConsumerQueue {
|
||||
ProducerConsumerQueue(const ProducerConsumerQueue &) = delete;
|
||||
ProducerConsumerQueue &operator=(const ProducerConsumerQueue &) = delete;
|
||||
|
||||
ProducerConsumerQueue(ProducerConsumerQueue &&other) {
|
||||
// ProducerConsumerQueue(ProducerConsumerQueue &&other) {
|
||||
// size_ = other.size_;
|
||||
// records_ = other.records_;
|
||||
// other.records_ = nullptr;
|
||||
// readIndex_ = other.readIndex_.load(std::memory_order_acquire);
|
||||
// writeIndex_ = other.writeIndex_.load(std::memory_order_acquire);
|
||||
// }
|
||||
|
||||
ProducerConsumerQueue(ProducerConsumerQueue&& other) noexcept {
|
||||
size_ = other.size_;
|
||||
records_ = other.records_;
|
||||
readIndex_.store(other.readIndex_.load(std::memory_order_acquire),
|
||||
std::memory_order_relaxed);
|
||||
writeIndex_.store(other.writeIndex_.load(std::memory_order_acquire),
|
||||
std::memory_order_relaxed);
|
||||
|
||||
other.records_ = nullptr;
|
||||
readIndex_ = other.readIndex_.load(std::memory_order_acquire);
|
||||
writeIndex_ = other.writeIndex_.load(std::memory_order_acquire);
|
||||
other.size_ = 0;
|
||||
other.readIndex_.store(0, std::memory_order_relaxed);
|
||||
other.writeIndex_.store(0, std::memory_order_relaxed);
|
||||
}
|
||||
ProducerConsumerQueue &operator=(ProducerConsumerQueue &&other) {
|
||||
|
||||
// ProducerConsumerQueue &operator=(ProducerConsumerQueue &&other) {
|
||||
// size_ = other.size_;
|
||||
// records_ = other.records_;
|
||||
// other.records_ = nullptr;
|
||||
// readIndex_ = other.readIndex_.load(std::memory_order_acquire);
|
||||
// writeIndex_ = other.writeIndex_.load(std::memory_order_acquire);
|
||||
// return *this;
|
||||
// }
|
||||
|
||||
ProducerConsumerQueue& operator=(ProducerConsumerQueue&& other) {
|
||||
if (this == &other) return *this;
|
||||
|
||||
//Destroy existing elements and free old storage
|
||||
if (records_ && !std::is_trivially_destructible<T>::value) {
|
||||
size_t r = readIndex_.load(std::memory_order_relaxed);
|
||||
size_t w = writeIndex_.load(std::memory_order_relaxed);
|
||||
while (r != w) {
|
||||
records_[r].~T();
|
||||
if (++r == size_) r = 0;
|
||||
}
|
||||
}
|
||||
std::free(records_);
|
||||
|
||||
//Steal other's state
|
||||
size_ = other.size_;
|
||||
records_ = other.records_;
|
||||
readIndex_.store( other.readIndex_.load(std::memory_order_acquire), std::memory_order_relaxed );
|
||||
writeIndex_.store( other.writeIndex_.load(std::memory_order_acquire), std::memory_order_relaxed );
|
||||
|
||||
//leave 'other' empty and harmless
|
||||
other.records_ = nullptr;
|
||||
readIndex_ = other.readIndex_.load(std::memory_order_acquire);
|
||||
writeIndex_ = other.writeIndex_.load(std::memory_order_acquire);
|
||||
other.size_ = 0;
|
||||
other.readIndex_.store(0, std::memory_order_relaxed);
|
||||
other.writeIndex_.store(0, std::memory_order_relaxed);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,34 +26,33 @@ def _get_class(name, cluster_size, dtype):
|
||||
|
||||
|
||||
|
||||
def ClusterFinder(image_size, saved_cluster_size, checked_cluster_size, n_sigma=5, dtype = np.int32, capacity = 1024):
|
||||
def ClusterFinder(image_size, cluster_size, n_sigma=5, dtype = np.int32, capacity = 1024):
|
||||
"""
|
||||
Factory function to create a ClusterFinder object. Provides a cleaner syntax for
|
||||
the templated ClusterFinder in C++.
|
||||
"""
|
||||
cls = _get_class("ClusterFinder", saved_cluster_size, dtype)
|
||||
return cls(image_size, n_sigma=n_sigma, capacity=capacity, cluster_size_x=checked_cluster_size[0], cluster_size_y=checked_cluster_size[1])
|
||||
cls = _get_class("ClusterFinder", cluster_size, dtype)
|
||||
return cls(image_size, n_sigma=n_sigma, capacity=capacity)
|
||||
|
||||
|
||||
|
||||
def ClusterFinderMT(image_size, saved_cluster_size = (3,3), checked_cluster_size = (3,3), dtype=np.int32, n_sigma=5, capacity = 1024, n_threads = 3):
|
||||
def ClusterFinderMT(image_size, cluster_size = (3,3), dtype=np.int32, n_sigma=5, capacity = 1024, n_threads = 3):
|
||||
"""
|
||||
Factory function to create a ClusterFinderMT object. Provides a cleaner syntax for
|
||||
the templated ClusterFinderMT in C++.
|
||||
"""
|
||||
|
||||
cls = _get_class("ClusterFinderMT", saved_cluster_size, dtype)
|
||||
return cls(image_size, n_sigma=n_sigma, capacity=capacity, n_threads=n_threads, cluster_size_x=checked_cluster_size[0], cluster_size_y=checked_cluster_size[1])
|
||||
cls = _get_class("ClusterFinderMT", cluster_size, dtype)
|
||||
return cls(image_size, n_sigma=n_sigma, capacity=capacity, n_threads=n_threads)
|
||||
|
||||
|
||||
|
||||
def ClusterCollector(clusterfindermt, cluster_size = (3,3), dtype=np.int32):
|
||||
def ClusterCollector(clusterfindermt, dtype=np.int32):
|
||||
"""
|
||||
Factory function to create a ClusterCollector object. Provides a cleaner syntax for
|
||||
the templated ClusterCollector in C++.
|
||||
"""
|
||||
|
||||
cls = _get_class("ClusterCollector", cluster_size, dtype)
|
||||
|
||||
cls = _get_class("ClusterCollector", clusterfindermt.cluster_size, dtype)
|
||||
return cls(clusterfindermt)
|
||||
|
||||
def ClusterFileSink(clusterfindermt, cluster_file, dtype=np.int32):
|
||||
|
||||
@@ -17,7 +17,7 @@ from .ClusterVector import ClusterVector
|
||||
from ._aare import fit_gaus, fit_pol1, fit_scurve, fit_scurve2
|
||||
from ._aare import Interpolator
|
||||
from ._aare import calculate_eta2
|
||||
|
||||
from ._aare import reduce_to_2x2, reduce_to_3x3
|
||||
|
||||
from ._aare import apply_custom_weights
|
||||
|
||||
|
||||
@@ -24,7 +24,8 @@ void define_Cluster(py::module &m, const std::string &typestr) {
|
||||
py::class_<Cluster<Type, ClusterSizeX, ClusterSizeY, CoordType>>(
|
||||
m, class_name.c_str(), py::buffer_protocol())
|
||||
|
||||
.def(py::init([](uint8_t x, uint8_t y, py::array_t<Type> data) {
|
||||
.def(py::init([](uint8_t x, uint8_t y,
|
||||
py::array_t<Type, py::array::forcecast> data) {
|
||||
py::buffer_info buf_info = data.request();
|
||||
Cluster<Type, ClusterSizeX, ClusterSizeY, CoordType> cluster;
|
||||
cluster.x = x;
|
||||
@@ -34,31 +35,58 @@ void define_Cluster(py::module &m, const std::string &typestr) {
|
||||
cluster.data[i] = r(i);
|
||||
}
|
||||
return cluster;
|
||||
}));
|
||||
}))
|
||||
|
||||
/*
|
||||
//TODO! Review if to keep or not
|
||||
.def_property(
|
||||
"data",
|
||||
[](ClusterType &c) -> py::array {
|
||||
return py::array(py::buffer_info(
|
||||
c.data, sizeof(Type),
|
||||
py::format_descriptor<Type>::format(), // Type
|
||||
// format
|
||||
1, // Number of dimensions
|
||||
{static_cast<ssize_t>(ClusterSizeX *
|
||||
ClusterSizeY)}, // Shape (flattened)
|
||||
{sizeof(Type)} // Stride (step size between elements)
|
||||
));
|
||||
// TODO! Review if to keep or not
|
||||
.def_property_readonly(
|
||||
"data",
|
||||
[](Cluster<Type, ClusterSizeX, ClusterSizeY, CoordType> &c)
|
||||
-> py::array {
|
||||
return py::array(py::buffer_info(
|
||||
c.data.data(), sizeof(Type),
|
||||
py::format_descriptor<Type>::format(), // Type
|
||||
// format
|
||||
2, // Number of dimensions
|
||||
{static_cast<ssize_t>(ClusterSizeX),
|
||||
static_cast<ssize_t>(ClusterSizeY)}, // Shape (flattened)
|
||||
{sizeof(Type) * ClusterSizeY, sizeof(Type)}
|
||||
// Stride (step size between elements)
|
||||
));
|
||||
})
|
||||
|
||||
.def_readonly("x",
|
||||
&Cluster<Type, ClusterSizeX, ClusterSizeY, CoordType>::x)
|
||||
|
||||
.def_readonly("y",
|
||||
&Cluster<Type, ClusterSizeX, ClusterSizeY, CoordType>::y);
|
||||
}
|
||||
|
||||
template <typename T, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
|
||||
typename CoordType = int16_t>
|
||||
void reduce_to_3x3(py::module &m) {
|
||||
|
||||
m.def(
|
||||
"reduce_to_3x3",
|
||||
[](const Cluster<T, ClusterSizeX, ClusterSizeY, CoordType> &cl) {
|
||||
return reduce_to_3x3(cl);
|
||||
},
|
||||
[](ClusterType &c, py::array_t<Type> arr) {
|
||||
py::buffer_info buf_info = arr.request();
|
||||
Type *ptr = static_cast<Type *>(buf_info.ptr);
|
||||
std::copy(ptr, ptr + ClusterSizeX * ClusterSizeY,
|
||||
c.data); // TODO dont iterate over centers!!!
|
||||
py::return_value_policy::move,
|
||||
"Reduce cluster to 3x3 subcluster by taking the 3x3 subcluster with "
|
||||
"the highest photon energy.");
|
||||
}
|
||||
|
||||
});
|
||||
*/
|
||||
template <typename T, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
|
||||
typename CoordType = int16_t>
|
||||
void reduce_to_2x2(py::module &m) {
|
||||
|
||||
m.def(
|
||||
"reduce_to_2x2",
|
||||
[](const Cluster<T, ClusterSizeX, ClusterSizeY, CoordType> &cl) {
|
||||
return reduce_to_2x2(cl);
|
||||
},
|
||||
py::return_value_policy::move,
|
||||
"Reduce cluster to 2x2 subcluster by taking the 2x2 subcluster with "
|
||||
"the highest photon energy.");
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
@@ -30,9 +30,8 @@ void define_ClusterFinder(py::module &m, const std::string &typestr) {
|
||||
|
||||
py::class_<ClusterFinder<ClusterType, uint16_t, pd_type>>(
|
||||
m, class_name.c_str())
|
||||
.def(py::init<Shape<2>, pd_type, size_t, uint32_t, uint32_t>(), py::arg("image_size"),
|
||||
py::arg("n_sigma") = 5.0, py::arg("capacity") = 1'000'000,
|
||||
py::arg("cluster_size_x") = 3, py::arg("cluster_size_y") = 3)
|
||||
.def(py::init<Shape<2>, pd_type, size_t>(), py::arg("image_size"),
|
||||
py::arg("n_sigma") = 5.0, py::arg("capacity") = 1'000'000)
|
||||
.def("push_pedestal_frame",
|
||||
[](ClusterFinder<ClusterType, uint16_t, pd_type> &self,
|
||||
py::array_t<uint16_t> frame) {
|
||||
|
||||
@@ -30,10 +30,9 @@ void define_ClusterFinderMT(py::module &m, const std::string &typestr) {
|
||||
|
||||
py::class_<ClusterFinderMT<ClusterType, uint16_t, pd_type>>(
|
||||
m, class_name.c_str())
|
||||
.def(py::init<Shape<2>, pd_type, size_t, size_t, uint32_t, uint32_t>(),
|
||||
.def(py::init<Shape<2>, pd_type, size_t, size_t>(),
|
||||
py::arg("image_size"), py::arg("n_sigma") = 5.0,
|
||||
py::arg("capacity") = 2048, py::arg("n_threads") = 3,
|
||||
py::arg("cluster_size_x") = 3, py::arg("cluster_size_y") = 3)
|
||||
py::arg("capacity") = 2048, py::arg("n_threads") = 3)
|
||||
.def("push_pedestal_frame",
|
||||
[](ClusterFinderMT<ClusterType, uint16_t, pd_type> &self,
|
||||
py::array_t<uint16_t> frame) {
|
||||
|
||||
@@ -104,4 +104,47 @@ void define_ClusterVector(py::module &m, const std::string &typestr) {
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Type, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
|
||||
typename CoordType = uint16_t>
|
||||
void define_2x2_reduction(py::module &m) {
|
||||
m.def(
|
||||
"reduce_to_2x2",
|
||||
[](const ClusterVector<
|
||||
Cluster<Type, ClusterSizeX, ClusterSizeY, CoordType>> &cv) {
|
||||
return new ClusterVector<Cluster<Type, 2, 2, CoordType>>(
|
||||
reduce_to_2x2(cv));
|
||||
},
|
||||
R"(
|
||||
|
||||
Reduce cluster to 2x2 subcluster by taking the 2x2 subcluster with
|
||||
the highest photon energy."
|
||||
Parameters
|
||||
----------
|
||||
cv : ClusterVector
|
||||
)",
|
||||
py::arg("clustervector"));
|
||||
}
|
||||
|
||||
template <typename Type, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
|
||||
typename CoordType = uint16_t>
|
||||
void define_3x3_reduction(py::module &m) {
|
||||
|
||||
m.def(
|
||||
"reduce_to_3x3",
|
||||
[](const ClusterVector<
|
||||
Cluster<Type, ClusterSizeX, ClusterSizeY, CoordType>> &cv) {
|
||||
return new ClusterVector<Cluster<Type, 3, 3, CoordType>>(
|
||||
reduce_to_3x3(cv));
|
||||
},
|
||||
R"(
|
||||
|
||||
Reduce cluster to 3x3 subcluster by taking the 3x3 subcluster with
|
||||
the highest photon energy."
|
||||
Parameters
|
||||
----------
|
||||
cv : ClusterVector
|
||||
)",
|
||||
py::arg("clustervector"));
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
@@ -47,7 +47,9 @@ double, 'f' for float)
|
||||
define_ClusterFileSink<T, N, M, U>(m, "Cluster" #N "x" #M #TYPE_CODE); \
|
||||
define_ClusterCollector<T, N, M, U>(m, "Cluster" #N "x" #M #TYPE_CODE); \
|
||||
define_Cluster<T, N, M, U>(m, #N "x" #M #TYPE_CODE); \
|
||||
register_calculate_eta<T, N, M, U>(m);
|
||||
register_calculate_eta<T, N, M, U>(m); \
|
||||
define_2x2_reduction<T, N, M, U>(m); \
|
||||
reduce_to_2x2<T, N, M, U>(m);
|
||||
|
||||
PYBIND11_MODULE(_aare, m) {
|
||||
define_file_io_bindings(m);
|
||||
@@ -85,8 +87,29 @@ PYBIND11_MODULE(_aare, m) {
|
||||
DEFINE_CLUSTER_BINDINGS(double, 9, 9, uint16_t, d);
|
||||
DEFINE_CLUSTER_BINDINGS(float, 9, 9, uint16_t, f);
|
||||
|
||||
DEFINE_CLUSTER_BINDINGS(int, 21, 21, uint16_t, i);
|
||||
DEFINE_CLUSTER_BINDINGS(double, 21, 21, uint16_t, d);
|
||||
DEFINE_CLUSTER_BINDINGS(float, 21, 21, uint16_t, f);
|
||||
|
||||
define_3x3_reduction<int, 3, 3, uint16_t>(m);
|
||||
define_3x3_reduction<double, 3, 3, uint16_t>(m);
|
||||
define_3x3_reduction<float, 3, 3, uint16_t>(m);
|
||||
define_3x3_reduction<int, 5, 5, uint16_t>(m);
|
||||
define_3x3_reduction<double, 5, 5, uint16_t>(m);
|
||||
define_3x3_reduction<float, 5, 5, uint16_t>(m);
|
||||
define_3x3_reduction<int, 7, 7, uint16_t>(m);
|
||||
define_3x3_reduction<double, 7, 7, uint16_t>(m);
|
||||
define_3x3_reduction<float, 7, 7, uint16_t>(m);
|
||||
define_3x3_reduction<int, 9, 9, uint16_t>(m);
|
||||
define_3x3_reduction<double, 9, 9, uint16_t>(m);
|
||||
define_3x3_reduction<float, 9, 9, uint16_t>(m);
|
||||
|
||||
reduce_to_3x3<int, 3, 3, uint16_t>(m);
|
||||
reduce_to_3x3<double, 3, 3, uint16_t>(m);
|
||||
reduce_to_3x3<float, 3, 3, uint16_t>(m);
|
||||
reduce_to_3x3<int, 5, 5, uint16_t>(m);
|
||||
reduce_to_3x3<double, 5, 5, uint16_t>(m);
|
||||
reduce_to_3x3<float, 5, 5, uint16_t>(m);
|
||||
reduce_to_3x3<int, 7, 7, uint16_t>(m);
|
||||
reduce_to_3x3<double, 7, 7, uint16_t>(m);
|
||||
reduce_to_3x3<float, 7, 7, uint16_t>(m);
|
||||
reduce_to_3x3<int, 9, 9, uint16_t>(m);
|
||||
reduce_to_3x3<double, 9, 9, uint16_t>(m);
|
||||
reduce_to_3x3<float, 9, 9, uint16_t>(m);
|
||||
}
|
||||
|
||||
@@ -101,6 +101,27 @@ def test_cluster_finder():
|
||||
assert clusters.size == 0
|
||||
|
||||
|
||||
def test_2x2_reduction():
|
||||
"""Test 2x2 Reduction"""
|
||||
cluster = _aare.Cluster3x3i(5,5,np.array([1, 1, 1, 2, 3, 1, 2, 2, 1], dtype=np.int32))
|
||||
|
||||
reduced_cluster = _aare.reduce_to_2x2(cluster)
|
||||
|
||||
assert reduced_cluster.x == 4
|
||||
assert reduced_cluster.y == 5
|
||||
assert (reduced_cluster.data == np.array([[2, 3], [2, 2]], dtype=np.int32)).all()
|
||||
|
||||
|
||||
def test_3x3_reduction():
|
||||
"""Test 3x3 Reduction"""
|
||||
cluster = _aare.Cluster5x5d(5,5,np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 2.0, 2.0, 3.0,
|
||||
1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], dtype=np.double))
|
||||
|
||||
reduced_cluster = _aare.reduce_to_3x3(cluster)
|
||||
|
||||
assert reduced_cluster.x == 4
|
||||
assert reduced_cluster.y == 5
|
||||
assert (reduced_cluster.data == np.array([[1.0, 2.0, 1.0], [2.0, 2.0, 3.0], [1.0, 2.0, 1.0]], dtype=np.double)).all()
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import time
|
||||
from pathlib import Path
|
||||
import pickle
|
||||
|
||||
from aare import ClusterFile
|
||||
from aare import ClusterFile, ClusterVector
|
||||
from aare import _aare
|
||||
from conftest import test_data_path
|
||||
|
||||
@@ -51,4 +51,36 @@ def test_make_a_hitmap_from_cluster_vector():
|
||||
# print(img)
|
||||
# print(ref)
|
||||
assert (img == ref).all()
|
||||
|
||||
|
||||
|
||||
def test_2x2_reduction():
|
||||
cv = ClusterVector((3,3))
|
||||
|
||||
cv.push_back(_aare.Cluster3x3i(5, 5, np.array([1, 1, 1, 2, 3, 1, 2, 2, 1], dtype=np.int32)))
|
||||
cv.push_back(_aare.Cluster3x3i(5, 5, np.array([2, 2, 1, 2, 3, 1, 1, 1, 1], dtype=np.int32)))
|
||||
|
||||
reduced_cv = np.array(_aare.reduce_to_2x2(cv), copy=False)
|
||||
|
||||
assert reduced_cv.size == 2
|
||||
assert reduced_cv[0]["x"] == 4
|
||||
assert reduced_cv[0]["y"] == 5
|
||||
assert (reduced_cv[0]["data"] == np.array([[2, 3], [2, 2]], dtype=np.int32)).all()
|
||||
assert reduced_cv[1]["x"] == 4
|
||||
assert reduced_cv[1]["y"] == 6
|
||||
assert (reduced_cv[1]["data"] == np.array([[2, 2], [2, 3]], dtype=np.int32)).all()
|
||||
|
||||
|
||||
def test_3x3_reduction():
|
||||
cv = _aare.ClusterVector_Cluster5x5d()
|
||||
|
||||
cv.push_back(_aare.Cluster5x5d(5,5,np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 2.0, 2.0, 3.0,
|
||||
1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], dtype=np.double)))
|
||||
cv.push_back(_aare.Cluster5x5d(5,5,np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 2.0, 2.0, 3.0,
|
||||
1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], dtype=np.double)))
|
||||
|
||||
reduced_cv = np.array(_aare.reduce_to_3x3(cv), copy=False)
|
||||
|
||||
assert reduced_cv.size == 2
|
||||
assert reduced_cv[0]["x"] == 4
|
||||
assert reduced_cv[0]["y"] == 5
|
||||
assert (reduced_cv[0]["data"] == np.array([[1.0, 2.0, 1.0], [2.0, 2.0, 3.0], [1.0, 2.0, 1.0]], dtype=np.double)).all()
|
||||
@@ -18,4 +18,86 @@ TEST_CASE("Test sum of Cluster", "[.cluster]") {
|
||||
Cluster<int, 2, 2> cluster{0, 0, {1, 2, 3, 4}};
|
||||
|
||||
CHECK(cluster.sum() == 10);
|
||||
}
|
||||
|
||||
using ClusterTypes = std::variant<Cluster<int, 2, 2>, Cluster<int, 3, 3>,
|
||||
Cluster<int, 5, 5>, Cluster<int, 2, 3>>;
|
||||
|
||||
using ClusterTypesLargerThan2x2 =
|
||||
std::variant<Cluster<int, 3, 3>, Cluster<int, 4, 4>, Cluster<int, 5, 5>>;
|
||||
|
||||
TEST_CASE("Test reduce to 2x2 Cluster", "[.cluster]") {
|
||||
auto [cluster, expected_reduced_cluster] = GENERATE(
|
||||
std::make_tuple(ClusterTypes{Cluster<int, 2, 2>{5, 5, {1, 2, 3, 4}}},
|
||||
Cluster<int, 2, 2>{4, 6, {1, 2, 3, 4}}),
|
||||
std::make_tuple(
|
||||
ClusterTypes{Cluster<int, 3, 3>{5, 5, {1, 1, 1, 1, 3, 2, 1, 2, 2}}},
|
||||
Cluster<int, 2, 2>{5, 5, {3, 2, 2, 2}}),
|
||||
std::make_tuple(
|
||||
ClusterTypes{Cluster<int, 3, 3>{5, 5, {1, 1, 1, 2, 3, 1, 2, 2, 1}}},
|
||||
Cluster<int, 2, 2>{4, 5, {2, 3, 2, 2}}),
|
||||
std::make_tuple(
|
||||
ClusterTypes{Cluster<int, 3, 3>{5, 5, {2, 2, 1, 2, 3, 1, 1, 1, 1}}},
|
||||
Cluster<int, 2, 2>{4, 6, {2, 2, 2, 3}}),
|
||||
std::make_tuple(
|
||||
ClusterTypes{Cluster<int, 3, 3>{5, 5, {1, 2, 2, 1, 3, 2, 1, 1, 1}}},
|
||||
Cluster<int, 2, 2>{5, 6, {2, 2, 3, 2}}),
|
||||
std::make_tuple(ClusterTypes{Cluster<int, 5, 5>{
|
||||
5, 5, {1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 3,
|
||||
2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}},
|
||||
Cluster<int, 2, 2>{5, 6, {2, 2, 3, 2}}),
|
||||
std::make_tuple(ClusterTypes{Cluster<int, 5, 5>{
|
||||
5, 5, {1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 2, 3,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}},
|
||||
Cluster<int, 2, 2>{4, 6, {2, 2, 2, 3}}),
|
||||
std::make_tuple(
|
||||
ClusterTypes{Cluster<int, 2, 3>{5, 5, {2, 2, 3, 2, 1, 1}}},
|
||||
Cluster<int, 2, 2>{4, 6, {2, 2, 3, 2}}));
|
||||
|
||||
auto reduced_cluster = std::visit(
|
||||
[](const auto &clustertype) { return reduce_to_2x2(clustertype); },
|
||||
cluster);
|
||||
|
||||
CHECK(reduced_cluster.x == expected_reduced_cluster.x);
|
||||
CHECK(reduced_cluster.y == expected_reduced_cluster.y);
|
||||
CHECK(std::equal(reduced_cluster.data.begin(),
|
||||
reduced_cluster.data.begin() + 4,
|
||||
expected_reduced_cluster.data.begin()));
|
||||
}
|
||||
|
||||
TEST_CASE("Test reduce to 3x3 Cluster", "[.cluster]") {
|
||||
auto [cluster, expected_reduced_cluster] = GENERATE(
|
||||
std::make_tuple(ClusterTypesLargerThan2x2{Cluster<int, 3, 3>{
|
||||
5, 5, {1, 1, 1, 1, 3, 1, 1, 1, 1}}},
|
||||
Cluster<int, 3, 3>{5, 5, {1, 1, 1, 1, 3, 1, 1, 1, 1}}),
|
||||
std::make_tuple(
|
||||
ClusterTypesLargerThan2x2{Cluster<int, 4, 4>{
|
||||
5, 5, {2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1}}},
|
||||
Cluster<int, 3, 3>{4, 6, {2, 2, 1, 2, 2, 1, 1, 1, 3}}),
|
||||
std::make_tuple(
|
||||
ClusterTypesLargerThan2x2{Cluster<int, 4, 4>{
|
||||
5, 5, {1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 3, 1, 1, 1, 1, 1}}},
|
||||
Cluster<int, 3, 3>{5, 6, {1, 2, 2, 1, 2, 2, 1, 3, 1}}),
|
||||
std::make_tuple(
|
||||
ClusterTypesLargerThan2x2{Cluster<int, 4, 4>{
|
||||
5, 5, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 1, 1, 2, 2}}},
|
||||
Cluster<int, 3, 3>{5, 5, {1, 1, 1, 1, 3, 2, 1, 2, 2}}),
|
||||
std::make_tuple(
|
||||
ClusterTypesLargerThan2x2{Cluster<int, 4, 4>{
|
||||
5, 5, {1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 1, 2, 2, 1, 1}}},
|
||||
Cluster<int, 3, 3>{4, 5, {1, 1, 1, 2, 2, 3, 2, 2, 1}}),
|
||||
std::make_tuple(ClusterTypesLargerThan2x2{Cluster<int, 5, 5>{
|
||||
5, 5, {1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 3,
|
||||
1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1}}},
|
||||
Cluster<int, 3, 3>{4, 5, {1, 2, 1, 2, 2, 3, 1, 2, 1}}));
|
||||
|
||||
auto reduced_cluster = std::visit(
|
||||
[](const auto &clustertype) { return reduce_to_3x3(clustertype); },
|
||||
cluster);
|
||||
|
||||
CHECK(reduced_cluster.x == expected_reduced_cluster.x);
|
||||
CHECK(reduced_cluster.y == expected_reduced_cluster.y);
|
||||
CHECK(std::equal(reduced_cluster.data.begin(),
|
||||
reduced_cluster.data.begin() + 9,
|
||||
expected_reduced_cluster.data.begin()));
|
||||
}
|
||||
@@ -57,6 +57,7 @@ class ClusterFinderMTWrapper
|
||||
size_t m_sink_size() const { return this->m_sink.sizeGuess(); }
|
||||
};
|
||||
|
||||
|
||||
TEST_CASE("multithreaded cluster finder", "[.with-data]") {
|
||||
auto fpath =
|
||||
test_data_path() / "raw/moench03/cu_half_speed_master_4.json";
|
||||
@@ -81,7 +82,8 @@ TEST_CASE("multithreaded cluster finder", "[.with-data]") {
|
||||
CHECK(cf.m_input_queues_are_empty() == true);
|
||||
|
||||
for (size_t i = 0; i < n_frames_pd; ++i) {
|
||||
cf.find_clusters(file.read_frame().view<uint16_t>());
|
||||
auto frame = file.read_frame();
|
||||
cf.find_clusters(frame.view<uint16_t>());
|
||||
}
|
||||
|
||||
cf.stop();
|
||||
|
||||
20
src/Makefile
Normal file
20
src/Makefile
Normal file
@@ -0,0 +1,20 @@
|
||||
# Makefile
|
||||
CXX := g++
|
||||
CXXFLAGS := -std=c++17 -O0 -g
|
||||
INCLUDE := -I../include
|
||||
|
||||
SRC := ProducerConsumerQueue.test.cpp
|
||||
BIN := test_pcq
|
||||
|
||||
.PHONY: all clean run
|
||||
|
||||
all: $(BIN)
|
||||
|
||||
$(BIN): $(SRC)
|
||||
$(CXX) $(CXXFLAGS) $(INCLUDE) $< -o $@
|
||||
|
||||
run: $(BIN)
|
||||
./$(BIN)
|
||||
|
||||
clean:
|
||||
$(RM) $(BIN)
|
||||
83
src/ProducerConsumerQueue.test.cpp
Normal file
83
src/ProducerConsumerQueue.test.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
#include <iostream>
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "aare/ProducerConsumerQueue.hpp"
|
||||
|
||||
struct Tracker {
|
||||
static std::atomic<int> ctors;
|
||||
static std::atomic<int> dtors;
|
||||
static std::atomic<int> moves;
|
||||
static std::atomic<int> live;
|
||||
|
||||
std::string tag;
|
||||
std::vector<int> buf;
|
||||
|
||||
Tracker() = delete;
|
||||
explicit Tracker(int id)
|
||||
: tag("T" + std::to_string(id)), buf(1 << 18, id)
|
||||
{
|
||||
++ctors; ++live;
|
||||
}
|
||||
|
||||
Tracker(Tracker&& other) noexcept
|
||||
: tag(std::move(other.tag)), buf(std::move(other.buf))
|
||||
{
|
||||
++moves;
|
||||
++ctors;
|
||||
++live;
|
||||
}
|
||||
|
||||
Tracker& operator=(Tracker&&) = delete;
|
||||
Tracker(const Tracker&) = delete;
|
||||
Tracker& operator=(const Tracker&) = delete;
|
||||
|
||||
~Tracker()
|
||||
{
|
||||
++dtors; --live;
|
||||
}
|
||||
};
|
||||
|
||||
std::atomic<int> Tracker::ctors{0};
|
||||
std::atomic<int> Tracker::dtors{0};
|
||||
std::atomic<int> Tracker::moves{0};
|
||||
std::atomic<int> Tracker::live{0};
|
||||
|
||||
int main() {
|
||||
using Queue = aare::ProducerConsumerQueue<Tracker>;
|
||||
|
||||
// Scope make sure destructors have ran before we check the counters.
|
||||
{
|
||||
Queue q1(8);
|
||||
Queue q2(8);
|
||||
|
||||
for (int i = 0; i < 3; ++i) q2.write(Tracker(100 + i));
|
||||
for (int i = 0; i < 5; ++i) q1.write(Tracker(200 + i));
|
||||
|
||||
q2 = std::move(q1);
|
||||
|
||||
Tracker tmp(9999);
|
||||
if (auto* p = q2.frontPtr())
|
||||
{
|
||||
(void)p;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "ctors=" << Tracker::ctors.load()
|
||||
<< " dtors=" << Tracker::dtors.load()
|
||||
<< " moves=" << Tracker::moves.load()
|
||||
<< " live=" << Tracker::live.load()
|
||||
<< "\n";
|
||||
|
||||
bool ok = (Tracker::ctors.load() == Tracker::dtors.load()) && (Tracker::live.load() == 0);
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
std::cerr << "Leak or skipped destructors detected (move-assignment bug)\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << "No leaks; move-assignment cleans up correctly\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -7,6 +7,7 @@ Script to update VERSION file with semantic versioning if provided as an argumen
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
from datetime import datetime
|
||||
|
||||
from packaging.version import Version, InvalidVersion
|
||||
|
||||
@@ -26,9 +27,9 @@ def get_version():
|
||||
|
||||
# Check at least one argument is passed
|
||||
if len(sys.argv) < 2:
|
||||
return "0.0.0"
|
||||
|
||||
version = sys.argv[1]
|
||||
version = datetime.today().strftime('%Y.%-m.%-d')
|
||||
else:
|
||||
version = sys.argv[1]
|
||||
|
||||
try:
|
||||
v = Version(version) # normalize check if version follows PEP 440 specification
|
||||
@@ -54,4 +55,4 @@ def write_version_to_file(version):
|
||||
if __name__ == "__main__":
|
||||
|
||||
version = get_version()
|
||||
write_version_to_file(version)
|
||||
write_version_to_file(version)
|
||||
|
||||
Reference in New Issue
Block a user