added g0 calibration, pedestal and pixel counting

This commit is contained in:
froejdh_e
2025-07-22 16:42:09 +02:00
parent b898e1c8d0
commit 9a7713e98a
8 changed files with 379 additions and 24 deletions

View File

@@ -66,17 +66,28 @@ class NDView : public ArrayExpr<NDView<T, Ndim>, Ndim> {
: buffer_(buffer), strides_(c_strides<Ndim>(shape)), shape_(shape),
size_(std::accumulate(std::begin(shape), std::end(shape), 1,
std::multiplies<>())) {}
template <typename... Ix>
std::enable_if_t<sizeof...(Ix) == Ndim, T &> operator()(Ix... index) {
return buffer_[element_offset(strides_, index...)];
}
template <typename... Ix>
const std::enable_if_t<sizeof...(Ix) == Ndim, T &> operator()(Ix... index) const {
std::enable_if_t<sizeof...(Ix) == 1 && (Ndim > 1), NDView<T, Ndim - 1>> operator()(Ix... index) {
// return a view of the next dimension
std::array<ssize_t, Ndim - 1> new_shape{};
std::copy_n(shape_.begin() + 1, Ndim - 1, new_shape.begin());
return NDView<T, Ndim - 1>(&buffer_[element_offset(strides_, index...)],
new_shape);
}
template <typename... Ix>
std::enable_if_t<sizeof...(Ix) == Ndim, const T &> operator()(Ix... index) const {
return buffer_[element_offset(strides_, index...)];
}
ssize_t size() const { return static_cast<ssize_t>(size_); }
size_t total_bytes() const { return size_ * sizeof(T); }
std::array<ssize_t, Ndim> strides() const noexcept { return strides_; }
@@ -85,9 +96,19 @@ class NDView : public ArrayExpr<NDView<T, Ndim>, Ndim> {
T *end() { return buffer_ + size_; }
T const *begin() const { return buffer_; }
T const *end() const { return buffer_ + size_; }
T &operator()(ssize_t i) { return buffer_[i]; }
/**
* @brief Access element at index i.
*/
T &operator[](ssize_t i) { return buffer_[i]; }
const T &operator()(ssize_t i) const { return buffer_[i]; }
/**
* @brief Access element at index i.
*/
const T &operator[](ssize_t i) const { return buffer_[i]; }
bool operator==(const NDView &other) const {

View File

@@ -240,14 +240,14 @@ template <typename T> void VarClusterFinder<T>::first_pass() {
for (ssize_t i = 0; i < original_.size(); ++i) {
if (use_noise_map)
threshold_ = 5 * noiseMap(i);
binary_(i) = (original_(i) > threshold_);
threshold_ = 5 * noiseMap[i];
binary_[i] = (original_[i] > threshold_);
}
for (int i = 0; i < shape_[0]; ++i) {
for (int j = 0; j < shape_[1]; ++j) {
// do we have someting to process?
// do we have something to process?
if (binary_(i, j)) {
auto tmp = check_neighbours(i, j);
if (tmp != 0) {

View File

@@ -1,5 +1,7 @@
#pragma once
#include "aare/NDArray.hpp"
#include "aare/NDView.hpp"
#include "aare/defs.hpp"
#include "aare/utils/task.hpp"
#include <cstdint>
@@ -55,32 +57,227 @@ ALWAYS_INLINE std::pair<uint16_t, int16_t> get_value_and_gain(uint16_t raw) {
template <class T>
void apply_calibration_impl(NDView<T, 3> res, NDView<uint16_t, 3> raw_data,
NDView<T, 3> ped, NDView<T, 3> cal, int start,
int stop) {
NDView<T, 3> ped, NDView<T, 3> cal, int start,
int stop) {
for (int frame_nr = start; frame_nr != stop; ++frame_nr) {
for (int row = 0; row != raw_data.shape(1); ++row) {
for (int col = 0; col != raw_data.shape(2); ++col) {
auto [value, gain] = get_value_and_gain(raw_data(frame_nr, row, col));
auto [value, gain] =
get_value_and_gain(raw_data(frame_nr, row, col));
// Using multiplication does not seem to speed up the code here
// ADU/keV is the standard unit for the calibration which
// means rewriting the formula is not worth it.
res(frame_nr, row, col) =
(value - ped(gain, row, col)) / cal(gain, row, col); //TODO! use multiplication
(value - ped(gain, row, col)) / cal(gain, row, col);
}
}
}
}
template <class T>
void apply_calibration_impl(NDView<T, 3> res, NDView<uint16_t, 3> raw_data,
NDView<T, 2> ped, NDView<T, 2> cal, int start,
int stop) {
for (int frame_nr = start; frame_nr != stop; ++frame_nr) {
for (int row = 0; row != raw_data.shape(1); ++row) {
for (int col = 0; col != raw_data.shape(2); ++col) {
auto [value, gain] =
get_value_and_gain(raw_data(frame_nr, row, col));
// Using multiplication does not seem to speed up the code here
// ADU/keV is the standard unit for the calibration which
// means rewriting the formula is not worth it.
// ignore anything that is not gain 0
// TODO! deal with fixed gain?
if (gain == 0)
res(frame_nr, row, col) =
(value - ped(row, col)) / cal(row, col);
}
}
}
}
template <class T, ssize_t Ndim=3>
void apply_calibration(NDView<T, 3> res, NDView<uint16_t, 3> raw_data,
NDView<T, 3> ped, NDView<T, 3> cal,
NDView<T, Ndim> ped, NDView<T, Ndim> cal,
ssize_t n_threads = 4) {
std::vector<std::future<void>> futures;
futures.reserve(n_threads);
auto limits = split_task(0, raw_data.shape(0), n_threads);
for (const auto &lim : limits)
futures.push_back(std::async(&apply_calibration_impl<T>, res, raw_data, ped, cal,
lim.first, lim.second));
futures.push_back(std::async(
static_cast<void (*)(NDView<T, 3>, NDView<uint16_t, 3>,
NDView<T, Ndim>, NDView<T, Ndim>, int, int)>(
apply_calibration_impl),
res, raw_data, ped, cal, lim.first, lim.second));
for (auto &f : futures)
f.get();
}
std::pair<NDArray<size_t, 3>, NDArray<size_t, 3>>
sum_and_count_per_gain(NDView<uint16_t, 3> raw_data);
std::pair<NDArray<size_t, 2>, NDArray<size_t, 2>>
sum_and_count_g0(NDView<uint16_t, 3> raw_data);
template <typename T>
NDArray<T, 3> calculate_pedestal(NDView<uint16_t, 3> raw_data) {
auto [accumulator, count] = sum_and_count_per_gain(raw_data);
NDArray<T, 3> pedestal(
std::array<ssize_t, 3>{3, raw_data.shape(1), raw_data.shape(2)}, 0);
for (int gain = 0; gain < 3; ++gain) {
for (int row = 0; row < raw_data.shape(1); ++row) {
for (int col = 0; col < raw_data.shape(2); ++col) {
if (count(gain, row, col) != 0) {
pedestal(gain, row, col) =
static_cast<T>(accumulator(gain, row, col)) /
static_cast<T>(count(gain, row, col));
}
}
}
}
return pedestal;
}
template <typename T>
NDArray<T, 2> calculate_pedestal_g0(NDView<uint16_t, 3> raw_data) {
auto [accumulator, count] = sum_and_count_g0(raw_data);
NDArray<T, 2> pedestal(
std::array<ssize_t, 2>{raw_data.shape(1), raw_data.shape(2)}, 0);
for (int row = 0; row < raw_data.shape(1); ++row) {
for (int col = 0; col < raw_data.shape(2); ++col) {
if (count(row, col) != 0) {
pedestal(row, col) =
static_cast<T>(accumulator(row, col)) /
static_cast<T>(count(row, col));
}
}
}
return pedestal;
}
template <typename T>
NDArray<T, 2> calculate_pedestal_g0(NDView<uint16_t, 3> raw_data,
ssize_t n_threads) {
std::vector<std::future<std::pair<NDArray<size_t, 2>, NDArray<size_t, 2>>>>
futures;
futures.reserve(n_threads);
auto limits = split_task(0, raw_data.shape(0), n_threads);
// make subviews for each thread
std::vector<NDView<uint16_t, 3>> subviews;
for (const auto &lim : limits) {
subviews.emplace_back(
raw_data.data() + lim.first * raw_data.strides()[0],
std::array<ssize_t, 3>{lim.second - lim.first, raw_data.shape(1),
raw_data.shape(2)});
}
for (auto view : subviews) {
futures.push_back(std::async(
static_cast<std::pair<NDArray<size_t, 2>, NDArray<size_t, 2>> (*)(
NDView<uint16_t, 3>)>(&sum_and_count_g0),
view));
}
NDArray<size_t, 2> accumulator(
std::array<ssize_t, 2>{raw_data.shape(1), raw_data.shape(2)}, 0);
NDArray<size_t, 2> count(
std::array<ssize_t, 2>{raw_data.shape(1), raw_data.shape(2)}, 0);
for (auto &f : futures) {
auto [acc, cnt] = f.get();
accumulator += acc;
count += cnt;
}
NDArray<T, 2> pedestal(
std::array<ssize_t,2>{raw_data.shape(1), raw_data.shape(2)}, 0);
for (int gain = 0; gain < 3; ++gain) {
for (int row = 0; row < raw_data.shape(1); ++row) {
for (int col = 0; col < raw_data.shape(2); ++col) {
if (count(row, col) != 0) {
pedestal(row, col) =
static_cast<T>(accumulator(row, col)) /
static_cast<T>(count(row, col));
}
}
}
}
return pedestal;
}
template <typename T>
NDArray<T, 3> calculate_pedestal(NDView<uint16_t, 3> raw_data,
ssize_t n_threads) {
NDArray<int, 2> switched(
std::array<ssize_t, 2>{raw_data.shape(1), raw_data.shape(2)}, 0);
std::vector<std::future<std::pair<NDArray<size_t, 3>, NDArray<size_t, 3>>>>
futures;
futures.reserve(n_threads);
auto limits = split_task(0, raw_data.shape(0), n_threads);
// make subviews for each thread
std::vector<NDView<uint16_t, 3>> subviews;
for (const auto &lim : limits) {
subviews.emplace_back(
raw_data.data() + lim.first * raw_data.strides()[0],
std::array<ssize_t, 3>{lim.second - lim.first, raw_data.shape(1),
raw_data.shape(2)});
}
for (auto view : subviews) {
futures.push_back(std::async(
static_cast<std::pair<NDArray<size_t, 3>, NDArray<size_t, 3>> (*)(
NDView<uint16_t, 3>)>(&sum_and_count_per_gain),
view));
}
NDArray<size_t, 3> accumulator(
std::array<ssize_t, 3>{3, raw_data.shape(1), raw_data.shape(2)}, 0);
NDArray<size_t, 3> count(
std::array<ssize_t, 3>{3, raw_data.shape(1), raw_data.shape(2)}, 0);
for (auto &f : futures) {
auto [acc, cnt] = f.get();
accumulator += acc;
count += cnt;
}
NDArray<T, 3> pedestal(
std::array<ssize_t, 3>{3, raw_data.shape(1), raw_data.shape(2)}, 0);
for (int gain = 0; gain < 3; ++gain) {
for (int row = 0; row < raw_data.shape(1); ++row) {
for (int col = 0; col < raw_data.shape(2); ++col) {
if (count(gain, row, col) != 0) {
pedestal(gain, row, col) =
static_cast<T>(accumulator(gain, row, col)) /
static_cast<T>(count(gain, row, col));
}
}
}
}
return pedestal;
}
/**
* @brief Count the number of switching pixels in the raw data.
* This function counts the number of pixels that switch between G1 and G2 gain.
* It returns an NDArray with the number of switching pixels per pixel.
* @param raw_data The NDView containing the raw data
* @return An NDArray with the number of switching pixels per pixel
*/
NDArray<int, 2> count_switching_pixels(NDView<uint16_t, 3> raw_data);
/**
* @brief Count the number of switching pixels in the raw data.
* This function counts the number of pixels that switch between G1 and G2 gain.
* It returns an NDArray with the number of switching pixels per pixel.
* @param raw_data The NDView containing the raw data
* @param n_threads The number of threads to use for parallel processing
* @return An NDArray with the number of switching pixels per pixel
*/
NDArray<int, 2> count_switching_pixels(NDView<uint16_t, 3> raw_data,
ssize_t n_threads);
} // namespace aare