mirror of
https://github.com/slsdetectorgroup/aare.git
synced 2026-11-11 08:54:02 +01:00
- added transform_eta_values for easier debugging more control for the user - updated Documentation
447 lines
14 KiB
C++
447 lines
14 KiB
C++
// SPDX-License-Identifier: MPL-2.0
|
|
#pragma once
|
|
|
|
#include "aare/Cluster.hpp"
|
|
#include "aare/ClusterVector.hpp"
|
|
#include "aare/NDArray.hpp"
|
|
#include "aare/defs.hpp"
|
|
|
|
namespace aare {
|
|
|
|
enum class pixel : int {
|
|
pBottomLeft = 0,
|
|
pBottom = 1,
|
|
pBottomRight = 2,
|
|
pLeft = 3,
|
|
pCenter = 4,
|
|
pRight = 5,
|
|
pTopLeft = 6,
|
|
pTop = 7,
|
|
pTopRight = 8
|
|
};
|
|
|
|
// TODO: better to have sum after x,y
|
|
/**
|
|
* eta struct
|
|
*/
|
|
template <typename T> struct Eta2 {
|
|
/// @brief eta in x direction
|
|
double x{};
|
|
/// @brief eta in y direction
|
|
double y{};
|
|
/// @brief index of subcluster with highest energy value (given as corner
|
|
/// relative to cluster center)
|
|
corner c{0};
|
|
/// @brief photon energy (cluster sum)
|
|
T sum{};
|
|
};
|
|
|
|
/**
|
|
* @brief Calculate the eta2 values for all clusters in a ClusterVector
|
|
*/
|
|
template <typename ClusterType,
|
|
typename = std::enable_if_t<is_cluster_v<ClusterType>>>
|
|
std::vector<Eta2<typename ClusterType::value_type>>
|
|
calculate_eta2(const ClusterVector<ClusterType> &clusters) {
|
|
|
|
std::vector<Eta2<typename ClusterType::value_type>> eta2{};
|
|
eta2.reserve(clusters.size());
|
|
|
|
for (size_t i = 0; i < clusters.size(); i++) {
|
|
auto e = calculate_eta2(clusters[i]);
|
|
eta2.push_back(e);
|
|
}
|
|
|
|
return eta2;
|
|
}
|
|
|
|
/**
|
|
* @brief Calculate the full eta2 values for all clusters in a ClusterVector
|
|
*/
|
|
template <typename ClusterType,
|
|
typename = std::enable_if_t<is_cluster_v<ClusterType>>>
|
|
std::vector<Eta2<typename ClusterType::value_type>>
|
|
calculate_full_eta2(const ClusterVector<ClusterType> &clusters) {
|
|
std::vector<Eta2<typename ClusterType::value_type>> eta2{};
|
|
eta2.reserve(clusters.size());
|
|
|
|
for (size_t i = 0; i < clusters.size(); i++) {
|
|
auto e = calculate_full_eta2(clusters[i]);
|
|
eta2.push_back(e);
|
|
}
|
|
|
|
return eta2;
|
|
}
|
|
|
|
/**
|
|
* @brief Calculate eta3 for all 3x3 clusters in a ClusterVector
|
|
*/
|
|
template <typename ClusterType,
|
|
typename = std::enable_if_t<is_cluster_v<ClusterType>>>
|
|
std::vector<Eta2<typename ClusterType::value_type>>
|
|
calculate_eta3(const ClusterVector<ClusterType> &clusters) {
|
|
std::vector<Eta2<typename ClusterType::value_type>> eta2{};
|
|
eta2.reserve(clusters.size());
|
|
|
|
for (size_t i = 0; i < clusters.size(); i++) {
|
|
auto e = calculate_eta3(clusters[i]);
|
|
eta2.push_back(e);
|
|
}
|
|
|
|
return eta2;
|
|
}
|
|
|
|
/**
|
|
* @brief Calculate cross eta3 for all 3x3 clusters in a ClusterVector
|
|
*/
|
|
template <typename ClusterType,
|
|
typename = std::enable_if_t<is_cluster_v<ClusterType>>>
|
|
std::vector<Eta2<typename ClusterType::value_type>>
|
|
calculate_cross_eta3(const ClusterVector<ClusterType> &clusters) {
|
|
std::vector<Eta2<typename ClusterType::value_type>> eta2{};
|
|
eta2.reserve(clusters.size());
|
|
|
|
for (size_t i = 0; i < clusters.size(); i++) {
|
|
auto e = calculate_cross_eta3(clusters[i]);
|
|
eta2.push_back(e);
|
|
}
|
|
|
|
return eta2;
|
|
}
|
|
|
|
/**
|
|
* @brief helper function to calculate eta2 x and y values
|
|
* @param eta reference to the Eta2 object to update
|
|
* @param left_x value of the left pixel
|
|
* @param right_x value of the right pixel
|
|
* @param bottom_y value of the bottom pixel
|
|
* @param top_y value of the top pixel
|
|
*/
|
|
template <typename T>
|
|
inline void calculate_eta2(Eta2<T> &eta, const T left_x, const T right_x,
|
|
const T bottom_y, const T top_y) {
|
|
if ((right_x + left_x) != 0)
|
|
eta.x = static_cast<double>(right_x) /
|
|
static_cast<double>(right_x + left_x); // between (0,1) the
|
|
// closer to zero left
|
|
// value probably larger
|
|
if ((top_y + bottom_y) != 0)
|
|
eta.y = static_cast<double>(top_y) /
|
|
static_cast<double>(top_y + bottom_y); // between (0,1) the
|
|
// closer to zero bottom
|
|
// value probably larger
|
|
}
|
|
|
|
/**
|
|
* @brief Calculate the eta2 values for a generic sized cluster and return them
|
|
* in a Eta2 struct containing etay, etax and the index (as corner) of the
|
|
* respective 2x2 subcluster relative to the cluster center.
|
|
*/
|
|
template <typename T, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
|
|
typename CoordType = uint16_t>
|
|
Eta2<T>
|
|
calculate_eta2(const Cluster<T, ClusterSizeX, ClusterSizeY, CoordType> &cl) {
|
|
|
|
static_assert(ClusterSizeX > 1 && ClusterSizeY > 1);
|
|
Eta2<T> eta{};
|
|
|
|
size_t cluster_center_index =
|
|
(ClusterSizeX / 2) + (ClusterSizeY / 2) * ClusterSizeX;
|
|
|
|
auto max_sum = cl.max_sum_2x2();
|
|
eta.sum = max_sum.sum;
|
|
corner c = max_sum.index;
|
|
|
|
// subcluster top right from center
|
|
switch (c) {
|
|
case (corner::cTopLeft):
|
|
calculate_eta2(eta, cl.data[cluster_center_index - 1],
|
|
cl.data[cluster_center_index],
|
|
cl.data[cluster_center_index - ClusterSizeX],
|
|
cl.data[cluster_center_index]);
|
|
// dx = -1
|
|
// dy = -1
|
|
break;
|
|
case (corner::cTopRight):
|
|
calculate_eta2(eta, cl.data[cluster_center_index],
|
|
cl.data[cluster_center_index + 1],
|
|
cl.data[cluster_center_index - ClusterSizeX],
|
|
cl.data[cluster_center_index]);
|
|
// dx = 0
|
|
// dy = -1
|
|
break;
|
|
case (corner::cBottomLeft):
|
|
calculate_eta2(eta, cl.data[cluster_center_index - 1],
|
|
cl.data[cluster_center_index],
|
|
cl.data[cluster_center_index],
|
|
cl.data[cluster_center_index + ClusterSizeX]);
|
|
// dx = -1
|
|
// dy = 0
|
|
break;
|
|
case (corner::cBottomRight):
|
|
calculate_eta2(eta, cl.data[cluster_center_index],
|
|
cl.data[cluster_center_index + 1],
|
|
cl.data[cluster_center_index],
|
|
cl.data[cluster_center_index + ClusterSizeX]);
|
|
// dx = 0
|
|
// dy = 0
|
|
break;
|
|
}
|
|
|
|
eta.c = c;
|
|
|
|
return eta;
|
|
}
|
|
|
|
/**
|
|
* @brief Calculate the eta2 values for a generic sized cluster and return them
|
|
* in a Eta2 struct containing etay, etax and the index (as corner) of the
|
|
* respective 2x2 subcluster relative to the cluster center.
|
|
*/
|
|
template <typename T, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
|
|
typename CoordType>
|
|
Eta2<T> calculate_full_eta2(
|
|
const Cluster<T, ClusterSizeX, ClusterSizeY, CoordType> &cl) {
|
|
|
|
static_assert(ClusterSizeX > 1 && ClusterSizeY > 1);
|
|
Eta2<T> eta{};
|
|
|
|
constexpr size_t cluster_center_index =
|
|
(ClusterSizeX / 2) + (ClusterSizeY / 2) * ClusterSizeX;
|
|
|
|
auto max_sum = cl.max_sum_2x2();
|
|
eta.sum = max_sum.sum;
|
|
corner c = max_sum.index;
|
|
|
|
// subcluster top right from center
|
|
switch (c) {
|
|
case (corner::cTopLeft):
|
|
if (eta.sum != 0) {
|
|
eta.x = static_cast<double>(
|
|
cl.data[cluster_center_index] +
|
|
cl.data[cluster_center_index - ClusterSizeX]) /
|
|
static_cast<double>(eta.sum);
|
|
|
|
eta.y = static_cast<double>(cl.data[cluster_center_index - 1] +
|
|
cl.data[cluster_center_index]) /
|
|
static_cast<double>(eta.sum);
|
|
}
|
|
// dx = -1
|
|
// dy = -1
|
|
break;
|
|
case (corner::cTopRight):
|
|
if (eta.sum != 0) {
|
|
eta.x = static_cast<double>(
|
|
cl.data[cluster_center_index + 1] +
|
|
cl.data[cluster_center_index - ClusterSizeX + 1]) /
|
|
static_cast<double>(eta.sum);
|
|
eta.y = static_cast<double>(cl.data[cluster_center_index] +
|
|
cl.data[cluster_center_index + 1]) /
|
|
static_cast<double>(eta.sum);
|
|
}
|
|
// dx = 0
|
|
// dy = -1
|
|
break;
|
|
case (corner::cBottomLeft):
|
|
if (eta.sum != 0) {
|
|
eta.x = static_cast<double>(
|
|
cl.data[cluster_center_index] +
|
|
cl.data[cluster_center_index + ClusterSizeX]) /
|
|
static_cast<double>(eta.sum);
|
|
eta.y = static_cast<double>(
|
|
cl.data[cluster_center_index + ClusterSizeX] +
|
|
cl.data[cluster_center_index + ClusterSizeX - 1]) /
|
|
static_cast<double>(eta.sum);
|
|
}
|
|
// dx = -1
|
|
// dy = 0
|
|
break;
|
|
case (corner::cBottomRight):
|
|
if (eta.sum != 0) {
|
|
eta.x = static_cast<double>(
|
|
cl.data[cluster_center_index + 1] +
|
|
cl.data[cluster_center_index + ClusterSizeX + 1]) /
|
|
static_cast<double>(eta.sum);
|
|
eta.y = static_cast<double>(
|
|
cl.data[cluster_center_index + ClusterSizeX] +
|
|
cl.data[cluster_center_index + ClusterSizeX + 1]) /
|
|
static_cast<double>(eta.sum);
|
|
}
|
|
// dx = 0
|
|
// dy = 0
|
|
break;
|
|
}
|
|
|
|
eta.c = c;
|
|
|
|
return eta;
|
|
}
|
|
|
|
template <typename T>
|
|
Eta2<T> calculate_eta2(const Cluster<T, 2, 2, uint16_t> &cl) {
|
|
Eta2<T> eta{};
|
|
|
|
// TODO: maybe have as member function of cluster
|
|
const uint8_t photon_hit_index =
|
|
std::max_element(cl.data.begin(), cl.data.end()) - cl.data.begin();
|
|
|
|
eta.c = static_cast<corner>(3 - photon_hit_index);
|
|
|
|
switch (eta.c) {
|
|
case corner::cTopLeft:
|
|
calculate_eta2(eta, cl.data[2], cl.data[3], cl.data[1], cl.data[3]);
|
|
break;
|
|
case corner::cTopRight:
|
|
calculate_eta2(eta, cl.data[2], cl.data[3], cl.data[0], cl.data[2]);
|
|
break;
|
|
case corner::cBottomLeft:
|
|
calculate_eta2(eta, cl.data[0], cl.data[1], cl.data[1], cl.data[3]);
|
|
break;
|
|
case corner::cBottomRight:
|
|
calculate_eta2(eta, cl.data[0], cl.data[1], cl.data[0], cl.data[2]);
|
|
break;
|
|
}
|
|
|
|
eta.sum = cl.sum();
|
|
|
|
return eta;
|
|
}
|
|
|
|
template <typename T>
|
|
Eta2<T> calculate_full_eta2(const Cluster<T, 2, 2, uint16_t> &cl) {
|
|
|
|
Eta2<T> eta{};
|
|
|
|
eta.sum = cl.sum();
|
|
|
|
const uint8_t photon_hit_index =
|
|
std::max_element(cl.data.begin(), cl.data.end()) - cl.data.begin();
|
|
|
|
eta.c = static_cast<corner>(3 - photon_hit_index);
|
|
|
|
if (eta.sum != 0) {
|
|
eta.x = static_cast<double>(cl.data[1] + cl.data[3]) /
|
|
static_cast<double>(eta.sum);
|
|
eta.y = static_cast<double>(cl.data[2] + cl.data[3]) /
|
|
static_cast<double>(eta.sum);
|
|
}
|
|
|
|
return eta;
|
|
}
|
|
|
|
// TODO generalize
|
|
template <typename T>
|
|
Eta2<T> calculate_eta2(const Cluster<T, 1, 2, uint16_t> &cl) {
|
|
Eta2<T> eta{};
|
|
|
|
eta.x = 0;
|
|
eta.y = static_cast<double>(cl.data[1]) / cl.data[0];
|
|
eta.sum = cl.sum();
|
|
}
|
|
|
|
template <typename T>
|
|
Eta2<T> calculate_eta2(const Cluster<T, 2, 1, uint16_t> &cl) {
|
|
Eta2<T> eta{};
|
|
|
|
eta.x = static_cast<double>(cl.data[1]) / cl.data[0];
|
|
eta.y = 0;
|
|
eta.sum = cl.sum();
|
|
}
|
|
|
|
/**
|
|
* @brief calculates cross Eta3 for 3x3 cluster
|
|
* cross Eta3 calculates the eta by taking into account only the cross pixels
|
|
* {top, bottom, left, right, center}
|
|
*/
|
|
template <typename T, typename CoordType = uint16_t>
|
|
Eta2<T> calculate_cross_eta3(const Cluster<T, 3, 3, CoordType> &cl) {
|
|
|
|
Eta2<T> eta{};
|
|
|
|
T photon_energy = cl.sum();
|
|
|
|
eta.sum = photon_energy;
|
|
|
|
if ((cl.data[3] + cl.data[4] + cl.data[5]) != 0)
|
|
|
|
eta.x =
|
|
static_cast<double>(-cl.data[3] + cl.data[3 + 2]) /
|
|
|
|
static_cast<double>(cl.data[3] + cl.data[4] + cl.data[5]); // (-1,1)
|
|
|
|
if ((cl.data[1] + cl.data[4] + cl.data[7]) != 0)
|
|
|
|
eta.y = static_cast<double>(-cl.data[1] + cl.data[2 * 3 + 1]) /
|
|
|
|
static_cast<double>(cl.data[1] + cl.data[4] + cl.data[7]);
|
|
|
|
return eta;
|
|
}
|
|
|
|
template <typename T, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
|
|
typename CoordType = uint16_t>
|
|
Eta2<T> calculate_cross_eta3(
|
|
const Cluster<T, ClusterSizeX, ClusterSizeY, CoordType> &cl) {
|
|
|
|
static_assert(ClusterSizeX > 2 && ClusterSizeY > 2,
|
|
"calculate_eta3 only defined for clusters larger than 2x2");
|
|
|
|
if constexpr (ClusterSizeX != 3 || ClusterSizeY != 3) {
|
|
auto reduced_cluster = reduce_cluster_to_3x3(cl);
|
|
return calculate_cross_eta3(reduced_cluster);
|
|
} else {
|
|
return calculate_cross_eta3(cl);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief calculates Eta3 for 3x3 cluster
|
|
* It calculates the eta by taking into account all pixels in the 3x3 cluster
|
|
*/
|
|
template <typename T, typename CoordType = uint16_t>
|
|
Eta2<T> calculate_eta3(const Cluster<T, 3, 3, CoordType> &cl) {
|
|
|
|
Eta2<T> eta{};
|
|
|
|
T photon_energy = cl.sum();
|
|
|
|
eta.sum = photon_energy;
|
|
|
|
// TODO: how do we handle potential arithmetic overflows? - T could be
|
|
// uint16
|
|
if (photon_energy != 0) {
|
|
std::array<T, 2> column_sums{
|
|
static_cast<T>(cl.data[0] + cl.data[3] + cl.data[6]),
|
|
static_cast<T>(cl.data[2] + cl.data[5] + cl.data[8])};
|
|
|
|
eta.x = static_cast<double>(-column_sums[0] + column_sums[1]) /
|
|
static_cast<double>(photon_energy);
|
|
|
|
std::array<T, 2> row_sums{
|
|
static_cast<T>(cl.data[0] + cl.data[1] + cl.data[2]),
|
|
static_cast<T>(cl.data[6] + cl.data[7] + cl.data[8])};
|
|
|
|
eta.y = static_cast<double>(-row_sums[0] + row_sums[1]) /
|
|
static_cast<double>(photon_energy);
|
|
}
|
|
|
|
return eta;
|
|
}
|
|
|
|
template <typename T, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
|
|
typename CoordType = uint16_t>
|
|
Eta2<T>
|
|
calculate_eta3(const Cluster<T, ClusterSizeX, ClusterSizeY, CoordType> &cl) {
|
|
|
|
static_assert(ClusterSizeX > 2 && ClusterSizeY > 2,
|
|
"calculate_eta3 only defined for clusters larger than 2x2");
|
|
|
|
if constexpr (ClusterSizeX != 3 || ClusterSizeY != 3) {
|
|
auto reduced_cluster = reduce_cluster_to_3x3(cl);
|
|
return calculate_eta3(reduced_cluster);
|
|
} else {
|
|
return calculate_eta3(cl);
|
|
}
|
|
}
|
|
|
|
} // namespace aare
|