Compare commits

..

5 Commits

Author SHA1 Message Date
Erik Fröjdh
6c3524298f bumped version for release
All checks were successful
Build on RHEL8 / build (push) Successful in 3m13s
Build on RHEL9 / build (push) Successful in 3m24s
2025-08-22 09:52:24 +02:00
Erik Fröjdh
a0fb4900f0 Update RELEASE.md
All checks were successful
Build on RHEL8 / build (push) Successful in 3m7s
Build on RHEL9 / build (push) Successful in 3m10s
2025-08-18 12:16:44 +02:00
Erik Fröjdh
91d74110fa specified glibc in conda build (#222)
Fixed a runtime error on older linux systems, since by mistake we used
glibc from ubutu 24. Same code as in slsDetectorPackage now.
2025-08-18 12:14:54 +02:00
f54e76e6bf view is only allowed on l-value frame (#220)
Vadym accidentally called view() directly on an R-value frame, which
leads to a dangling view pointer.
Adjusted code such that compiler throws an error if called on an R-value
frame.

Co-authored-by: Erik Fröjdh <erik.frojdh@psi.ch>
2025-08-18 11:02:05 +02:00
JFMulvey
c6da36d10b Fixed the order of cluster.data being incorrect (#221)
All checks were successful
Build on RHEL8 / build (push) Successful in 3m4s
Build on RHEL9 / build (push) Successful in 3m11s
While using the cluster finder and saving a cluster, pixels which are
out of bounds are skipped. cluster.data should contain the pedestal
corrected ADU information of each pixel.

However, the counter "i" which keeps track of the position of
cluster.data is only incremented if the pixel was inside the bounds of
the frame.

This means that any clusters close to the frame's edges are not
construed properly. This means that if you want to extract a 3x3 from a
9x9 cluster, it can fail if the cluster data is not properly centered in
the pixel.

Fixed by moving i++ outside the bounds check.

Co-authored-by: Jonathan Mulvey <jonathan.mulvey@psi.ch>
2025-08-14 09:27:02 +02:00
13 changed files with 84 additions and 350 deletions

View File

@@ -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:

View File

@@ -1 +1 @@
2025.7.18
2025.8.22

View File

@@ -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]

View File

@@ -16,6 +16,8 @@ build:
requirements:
build:
- {{ compiler('c') }}
- {{ stdlib("c") }}
- {{ compiler('cxx') }}
- cmake
- ninja

View File

@@ -1,152 +0,0 @@
#pragma once
#include "aare/Frame.hpp"
#include "aare/NDArray.hpp"
#include "aare/NDView.hpp"
#include <cstddef>
//JMulvey
//This is a new way to do pedestals (inspired by Dominic's cluster finder)
//Instead of pedestal tracking, we split the data (photon data) up into chunks (say 50K frames)
//For each chunk, we look at the spectra and fit to the noise peak. When we run the cluster finder, we then use this chunked pedestal data
//The smaller the chunk size, the more accurate, but also the longer it takes to process.
//It is essentially a pre-processing step.
//Ideally this new class will do that processing.
//But for now we will just implement a method to pass in the chunked pedestal values directly (I have my own script which does it for now)
//I've cut this down a lot, knowing full well it'll need changing if we want to merge it with main (happy to do that once I get it work for what I need)
namespace aare {
/**
* @brief Calculate the pedestal of a series of frames. Can be used as
* standalone but mostly used in the ClusterFinder.
*
* @tparam SUM_TYPE type of the sum
*/
template <typename SUM_TYPE = double> class ChunkedPedestal {
uint32_t m_rows;
uint32_t m_cols;
uint32_t m_n_chunks;
uint64_t m_current_frame_number;
uint64_t m_current_chunk_number;
NDArray<SUM_TYPE, 3> m_mean;
NDArray<SUM_TYPE, 3> m_std;
uint32_t m_chunk_size;
public:
ChunkedPedestal(uint32_t rows, uint32_t cols, uint32_t chunk_size = 50000, uint32_t n_chunks = 10)
: m_rows(rows), m_cols(cols), m_chunk_size(chunk_size), m_n_chunks(n_chunks),
m_mean(NDArray<SUM_TYPE, 3>({n_chunks, rows, cols})), m_std(NDArray<SUM_TYPE, 3>({n_chunks, rows, cols})) {
assert(rows > 0 && cols > 0 && chunk_size > 0);
m_mean = 0;
m_std = 0;
m_current_frame_number = 0;
m_current_chunk_number = 0;
}
~ChunkedPedestal() = default;
NDArray<SUM_TYPE, 3> mean() { return m_mean; }
NDArray<SUM_TYPE, 3> std() { return m_std; }
void set_frame_number (uint64_t frame_number) {
m_current_frame_number = frame_number;
m_current_chunk_number = std::floor(frame_number / m_chunk_size);
//Debug
// if (frame_number % 10000 == 0)
// {
// std::cout << "frame_number: " << frame_number << " -> chunk_number: " << m_current_chunk_number << " pedestal at (100, 100): " << m_mean(m_current_chunk_number, 100, 100) << std::endl;
// }
if (m_current_chunk_number >= m_n_chunks)
{
m_current_chunk_number = 0;
throw std::runtime_error(
"Chunk number exceeds the number of chunks");
}
}
SUM_TYPE mean(const uint32_t row, const uint32_t col) const {
return m_mean(m_current_chunk_number, row, col);
}
SUM_TYPE std(const uint32_t row, const uint32_t col) const {
return m_std(m_current_chunk_number, row, col);
}
SUM_TYPE* get_mean_chunk_ptr() {
return &m_mean(m_current_chunk_number, 0, 0);
}
SUM_TYPE* get_std_chunk_ptr() {
return &m_std(m_current_chunk_number, 0, 0);
}
void clear() {
m_mean = 0;
m_std = 0;
m_n_chunks = 0;
}
//Probably don't need to do this one at a time, but let's keep it simple for now
template <typename T> void push_mean(NDView<T, 2> frame, uint32_t chunk_number) {
assert(frame.size() == m_rows * m_cols);
if (chunk_number >= m_n_chunks)
throw std::runtime_error(
"Chunk number is larger than the number of chunks");
// TODO! move away from m_rows, m_cols
if (frame.shape() != std::array<ssize_t, 2>{m_rows, m_cols}) {
throw std::runtime_error(
"Frame shape does not match pedestal shape");
}
for (size_t row = 0; row < m_rows; row++) {
for (size_t col = 0; col < m_cols; col++) {
push_mean<T>(row, col, chunk_number, frame(row, col));
}
}
}
template <typename T> void push_std(NDView<T, 2> frame, uint32_t chunk_number) {
assert(frame.size() == m_rows * m_cols);
if (chunk_number >= m_n_chunks)
throw std::runtime_error(
"Chunk number is larger than the number of chunks");
// TODO! move away from m_rows, m_cols
if (frame.shape() != std::array<ssize_t, 2>{m_rows, m_cols}) {
throw std::runtime_error(
"Frame shape does not match pedestal shape");
}
for (size_t row = 0; row < m_rows; row++) {
for (size_t col = 0; col < m_cols; col++) {
push_std<T>(row, col, chunk_number, frame(row, col));
}
}
}
// pixel level operations (should be refactored to allow users to implement
// their own pixel level operations)
template <typename T>
void push_mean(const uint32_t row, const uint32_t col, const uint32_t chunk_number, const T val_) {
m_mean(chunk_number, row, col) = val_;
}
template <typename T>
void push_std(const uint32_t row, const uint32_t col, const uint32_t chunk_number, const T val_) {
m_std(chunk_number, row, col) = val_;
}
// getter functions
uint32_t rows() const { return m_rows; }
uint32_t cols() const { return m_cols; }
};
} // namespace aare

View File

@@ -4,11 +4,9 @@
#include "aare/Dtype.hpp"
#include "aare/NDArray.hpp"
#include "aare/NDView.hpp"
// #include "aare/Pedestal.hpp"
#include "aare/ChunkedPedestal.hpp"
#include "aare/Pedestal.hpp"
#include "aare/defs.hpp"
#include <cstddef>
#include <iostream>
namespace aare {
@@ -19,13 +17,11 @@ class ClusterFinder {
const PEDESTAL_TYPE m_nSigma;
const PEDESTAL_TYPE c2;
const PEDESTAL_TYPE c3;
ChunkedPedestal<PEDESTAL_TYPE> m_pedestal;
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:
@@ -38,36 +34,25 @@ class ClusterFinder {
*
*/
ClusterFinder(Shape<2> image_size, PEDESTAL_TYPE nSigma = 5.0,
size_t capacity = 1000000,
uint32_t chunk_size = 50000, uint32_t n_chunks = 10,
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),
m_pedestal(image_size[0], image_size[1], chunk_size, n_chunks), m_clusters(capacity) {
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]
<< ", nSigma: " << nSigma << ", capacity: " << capacity;
}
// void push_pedestal_frame(NDView<FRAME_TYPE, 2> frame) {
// m_pedestal.push(frame);
// }
void push_pedestal_mean(NDView<PEDESTAL_TYPE, 2> frame, uint32_t chunk_number) {
m_pedestal.push_mean(frame, chunk_number);
void push_pedestal_frame(NDView<FRAME_TYPE, 2> frame) {
m_pedestal.push(frame);
}
void push_pedestal_std(NDView<PEDESTAL_TYPE, 2> frame, uint32_t chunk_number) {
m_pedestal.push_std(frame, chunk_number);
}
//This is here purely to keep the compiler happy for now
void push_pedestal_frame(NDView<FRAME_TYPE, 2> frame) {}
NDArray<PEDESTAL_TYPE, 2> pedestal() { return m_pedestal.mean(); }
NDArray<PEDESTAL_TYPE, 2> noise() { return m_pedestal.std(); }
void clear_pedestal() { m_pedestal.clear(); }
/**
/**
* @brief Move the clusters from the ClusterVector in the ClusterFinder to a
* new ClusterVector and return it.
* @param realloc_same_capacity if true the new ClusterVector will have the
@@ -84,13 +69,11 @@ class ClusterFinder {
return tmp;
}
void find_clusters(NDView<FRAME_TYPE, 2> frame, uint64_t frame_number = 0) {
// // TODO! deal with even size clusters
// // currently 3,3 -> +/- 1
// // 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
@@ -98,39 +81,27 @@ class ClusterFinder {
int has_center_pixel_y = ClusterSizeY % 2;
m_clusters.set_frame_number(frame_number);
m_pedestal.set_frame_number(frame_number);
auto mean_ptr = m_pedestal.get_mean_chunk_ptr();
auto std_ptr = m_pedestal.get_std_chunk_ptr();
for (int iy = 0; iy < frame.shape(0); iy++) {
size_t row_offset = iy * frame.shape(1);
for (int ix = 0; ix < frame.shape(1); ix++) {
// PEDESTAL_TYPE rms = m_pedestal.std(iy, ix);
PEDESTAL_TYPE rms = std_ptr[row_offset + ix];
if (rms == 0) continue;
PEDESTAL_TYPE max = std::numeric_limits<FRAME_TYPE>::min();
PEDESTAL_TYPE total = 0;
// What can we short circuit here?
// PEDESTAL_TYPE value = (frame(iy, ix) - m_pedestal.mean(iy, ix));
PEDESTAL_TYPE value = (frame(iy, ix) - mean_ptr[row_offset + ix]);
// What can we short circuit here?
PEDESTAL_TYPE rms = m_pedestal.std(iy, ix);
PEDESTAL_TYPE value = (frame(iy, ix) - m_pedestal.mean(iy, ix));
if (value < -m_nSigma * rms)
continue; // NEGATIVE_PEDESTAL go to next pixel
// TODO! No pedestal update???
for (int ir = -dy; ir < dy + has_center_pixel_y; ir++) {
size_t inner_row_offset = row_offset + (ir * frame.shape(1));
for (int ic = -dx; ic < dx + has_center_pixel_x; ic++) {
if (ix + ic >= 0 && ix + ic < frame.shape(1) &&
iy + ir >= 0 && iy + ir < frame.shape(0)) {
// if (m_pedestal.std(iy + ir, ix + ic) == 0) continue;
if (std_ptr[inner_row_offset + ix + ic] == 0) continue;
// PEDESTAL_TYPE val = frame(iy + ir, ix + ic) - m_pedestal.mean(iy + ir, ix + ic);
PEDESTAL_TYPE val = frame(iy + ir, ix + ic) - mean_ptr[inner_row_offset + ix + ic];
PEDESTAL_TYPE val =
frame(iy + ir, ix + ic) -
m_pedestal.mean(iy + ir, ix + ic);
total += val;
max = std::max(max, val);
@@ -138,64 +109,24 @@ class ClusterFinder {
}
}
// if (frame_number < 1)
// if ( (ix == 115 && iy == 122) )
// if ( (ix == 175 && iy == 175) )
// {
// // std::cout << std::endl;
// // std::cout << std::endl;
// // std::cout << "frame_number: " << frame_number << std::endl;
// // std::cout << "(" << ix << ", " << iy << "): " << std::endl;
// // std::cout << "frame.shape: (" << frame.shape(0) << ", " << frame.shape(1) << "): " << std::endl;
// // std::cout << "frame(175, 175): " << frame(175, 175) << std::endl;
// // std::cout << "frame(77, 98): " << frame(77, 98) << std::endl;
// // std::cout << "frame(82, 100): " << frame(82, 100) << std::endl;
// // std::cout << "frame(iy, ix): " << frame(iy, ix) << std::endl;
// // std::cout << "mean_ptr[row_offset + ix]: " << mean_ptr[row_offset + ix] << std::endl;
// // std::cout << "total: " << total << std::endl;
// std::cout << "(" << ix << ", " << iy << "): " << frame(iy, ix) << std::endl;
// }
// if ((max > m_nSigma * rms)) {
// if (value < max)
// continue; // Not max go to the next pixel
// // but also no pedestal update
// } else
if (total > c3 * m_nSigma * rms) {
if ((max > m_nSigma * rms)) {
if (value < max)
continue; // Not max go to the next pixel
// but also no pedestal update
} else if (total > c3 * m_nSigma * rms) {
// pass
} else {
// m_pedestal.push(iy, ix, frame(iy, ix)); // Safe option
//Not needed for chunked pedestal
// m_pedestal.push_fast(
// iy, ix,
// frame(iy,
// ix)); // Assume we have reached n_samples in the
// // pedestal, slight performance improvement
m_pedestal.push_fast(
iy, ix,
frame(iy,
ix)); // Assume we have reached n_samples in the
// pedestal, slight performance improvement
continue; // It was a pedestal value nothing to store
}
// Store cluster
if (value == max) {
// if (total < 0)
// {
// std::cout << "" << std::endl;
// std::cout << "frame_number: " << frame_number << std::endl;
// std::cout << "ix: " << ix << std::endl;
// std::cout << "iy: " << iy << std::endl;
// std::cout << "frame(iy, ix): " << frame(iy, ix) << std::endl;
// std::cout << "m_pedestal.mean(iy, ix): " << m_pedestal.mean(iy, ix) << std::endl;
// std::cout << "m_pedestal.std(iy, ix): " << m_pedestal.std(iy, ix) << std::endl;
// std::cout << "max: " << max << std::endl;
// std::cout << "value: " << value << std::endl;
// std::cout << "m_nSigma * rms: " << (m_nSigma * rms) << std::endl;
// std::cout << "total: " << total << std::endl;
// std::cout << "c3 * m_nSigma * rms: " << (c3 * m_nSigma * rms) << std::endl;
// }
ClusterType cluster{};
cluster.x = ix;
cluster.y = iy;
@@ -204,22 +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++) {
size_t inner_row_offset = row_offset + (ir * frame.shape(1));
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)) {
// if (m_pedestal.std(iy + ir, ix + ic) == 0) continue;
// if (std_ptr[inner_row_offset + ix + ic] == 0) continue;
// CT tmp = static_cast<CT>(frame(iy + ir, ix + ic)) - static_cast<CT>(m_pedestal.mean(iy + ir, ix + ic));
// CT tmp = 0;
if (std_ptr[inner_row_offset + ix + ic] != 0)
{
CT tmp = static_cast<CT>(frame(iy + ir, ix + ic)) - static_cast<CT>(mean_ptr[inner_row_offset + 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++;
}
@@ -233,4 +158,4 @@ class ClusterFinder {
}
};
} // namespace aare
} // namespace aare

View File

@@ -20,15 +20,9 @@ enum class FrameType {
struct FrameWrapper {
FrameType type;
uint64_t frame_number;
// NDArray<T, 2> data;
NDArray<uint16_t, 2> data;
// NDArray<double, 2> data;
// void* data_ptr;
// std::type_index data_type;
uint32_t chunk_number;
};
/**
* @brief ClusterFinderMT is a multi-threaded version of ClusterFinder. It uses
* a producer-consumer queue to distribute the frames to the threads. The
@@ -74,7 +68,6 @@ class ClusterFinderMT {
while (!m_stop_requested || !q->isEmpty()) {
if (FrameWrapper *frame = q->frontPtr(); frame != nullptr) {
switch (frame->type) {
case FrameType::DATA:
cf->find_clusters(frame->data.view(), frame->frame_number);
@@ -128,9 +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 chunk_size = 50000, uint32_t n_chunks = 10,
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: "
@@ -143,7 +134,7 @@ class ClusterFinderMT {
m_cluster_finders.push_back(
std::make_unique<
ClusterFinder<ClusterType, FRAME_TYPE, PEDESTAL_TYPE>>(
image_size, nSigma, capacity, chunk_size, n_chunks, 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));
@@ -217,7 +208,7 @@ class ClusterFinderMT {
*/
void push_pedestal_frame(NDView<FRAME_TYPE, 2> frame) {
FrameWrapper fw{FrameType::PEDESTAL, 0,
NDArray(frame), 0}; // TODO! copies the data!
NDArray(frame)}; // TODO! copies the data!
for (auto &queue : m_input_queues) {
while (!queue->write(fw)) {
@@ -226,23 +217,6 @@ class ClusterFinderMT {
}
}
void push_pedestal_mean(NDView<PEDESTAL_TYPE, 2> frame, uint32_t chunk_number) {
if (!m_processing_threads_stopped) {
throw std::runtime_error("ClusterFinderMT is still running");
}
for (auto &cf : m_cluster_finders) {
cf->push_pedestal_mean(frame, chunk_number);
}
}
void push_pedestal_std(NDView<PEDESTAL_TYPE, 2> frame, uint32_t chunk_number) {
if (!m_processing_threads_stopped) {
throw std::runtime_error("ClusterFinderMT is still running");
}
for (auto &cf : m_cluster_finders) {
cf->push_pedestal_std(frame, chunk_number);
}
}
/**
* @brief Push the frame to the queue of the next available thread. Function
* returns once the frame is in a queue.
@@ -250,10 +224,7 @@ class ClusterFinderMT {
*/
void find_clusters(NDView<FRAME_TYPE, 2> frame, uint64_t frame_number = 0) {
FrameWrapper fw{FrameType::DATA, frame_number,
NDArray(frame), 0}; // TODO! copies the data!
// std::cout << "frame(122, 115): " << frame(122, 115) << std::endl;
NDArray(frame)}; // TODO! copies the data!
while (!m_input_queues[m_current_thread % m_n_threads]->write(fw)) {
std::this_thread::sleep_for(m_default_wait);
}
@@ -310,4 +281,4 @@ class ClusterFinderMT {
// }
};
} // namespace aare
} // namespace aare

View File

@@ -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);

View File

@@ -26,24 +26,24 @@ 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, chunk_size=50000, n_chunks = 10):
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, chunk_size=chunk_size, n_chunks=n_chunks, 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, chunk_size=50000, n_chunks = 10):
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, chunk_size=chunk_size, n_chunks=n_chunks, 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)

View File

@@ -30,30 +30,14 @@ 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, uint32_t, uint32_t>(),
py::arg("image_size"), py::arg("n_sigma") = 5.0, py::arg("capacity") = 1'000'000,
py::arg("chunk_size") = 50'000, py::arg("n_chunks") = 10,
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) {
auto view = make_view_2d(frame);
self.push_pedestal_frame(view);
})
.def("push_pedestal_mean",
[](ClusterFinder<ClusterType, uint16_t, pd_type> &self,
py::array_t<double> frame, uint32_t chunk_number) {
auto view = make_view_2d(frame);
self.push_pedestal_mean(view, chunk_number);
})
.def("push_pedestal_std",
[](ClusterFinder<ClusterType, uint16_t, pd_type> &self,
py::array_t<double> frame, uint32_t chunk_number) {
auto view = make_view_2d(frame);
self.push_pedestal_std(view, chunk_number);
})
.def("clear_pedestal",
&ClusterFinder<ClusterType, uint16_t, pd_type>::clear_pedestal)
.def_property_readonly(

View File

@@ -30,31 +30,15 @@ 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, 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("chunk_size") = 50'000, py::arg("n_chunks") = 10,
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) {
auto view = make_view_2d(frame);
self.push_pedestal_frame(view);
})
.def("push_pedestal_mean",
[](ClusterFinderMT<ClusterType, uint16_t, pd_type> &self,
py::array_t<double> frame, uint32_t chunk_number) {
auto view = make_view_2d(frame);
self.push_pedestal_mean(view, chunk_number);
})
.def("push_pedestal_std",
[](ClusterFinderMT<ClusterType, uint16_t, pd_type> &self,
py::array_t<double> frame, uint32_t chunk_number) {
auto view = make_view_2d(frame);
self.push_pedestal_std(view, chunk_number);
})
.def(
"find_clusters",
[](ClusterFinderMT<ClusterType, uint16_t, pd_type> &self,

View File

@@ -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();

View File

@@ -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)