From 5614cb4673e115622267685268bbd409bb28aef2 Mon Sep 17 00:00:00 2001 From: froejdh_e Date: Wed, 5 Mar 2025 17:40:08 +0100 Subject: [PATCH 01/51] WIP --- CMakeLists.txt | 1 + include/aare/ClusterFile.hpp | 10 +++ include/aare/ClusterVector.hpp | 4 + include/aare/Interpolator.hpp | 29 ++++++ python/aare/__init__.py | 1 + python/examples/play.py | 56 +++++------- python/src/aare.code-workspace | 98 ++++++++++++++++++++ python/src/cluster.hpp | 10 ++- python/src/cluster_file.hpp | 5 ++ python/src/file.hpp | 2 + python/src/interpolation.hpp | 58 ++++++++++++ python/src/module.cpp | 2 + src/ClusterFile.cpp | 108 ++++++++++++++++++++-- src/Interpolator.cpp | 159 +++++++++++++++++++++++++++++++++ src/NDArray.test.cpp | 19 ++++ 15 files changed, 523 insertions(+), 39 deletions(-) create mode 100644 include/aare/Interpolator.hpp create mode 100644 python/src/aare.code-workspace create mode 100644 python/src/interpolation.hpp create mode 100644 src/Interpolator.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index cff4c75..bff2afe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -346,6 +346,7 @@ set(SourceFiles ${CMAKE_CURRENT_SOURCE_DIR}/src/geo_helpers.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/NumpyFile.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/NumpyHelpers.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Interpolator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/PixelMap.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/RawFile.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/RawSubFile.cpp diff --git a/include/aare/ClusterFile.hpp b/include/aare/ClusterFile.hpp index b796763..5bea342 100644 --- a/include/aare/ClusterFile.hpp +++ b/include/aare/ClusterFile.hpp @@ -8,11 +8,17 @@ namespace aare { +//TODO! Template this? struct Cluster3x3 { int16_t x; int16_t y; int32_t data[9]; }; +struct Cluster2x2 { + int16_t x; + int16_t y; + int32_t data[4]; +}; typedef enum { cBottomLeft = 0, @@ -37,6 +43,7 @@ struct Eta2 { double x; double y; corner c; + int32_t sum; }; struct ClusterAnalysis { @@ -97,6 +104,8 @@ class ClusterFile { */ ClusterVector read_clusters(size_t n_clusters); + ClusterVector read_clusters(size_t n_clusters, ROI roi); + /** * @brief Read a single frame from the file and return the clusters. The * cluster vector will have the frame number set. @@ -131,5 +140,6 @@ int analyze_cluster(Cluster3x3 &cl, int32_t *t2, int32_t *t3, char *quad, NDArray calculate_eta2(ClusterVector &clusters); Eta2 calculate_eta2(Cluster3x3 &cl); +Eta2 calculate_eta2(Cluster2x2 &cl); } // namespace aare diff --git a/include/aare/ClusterVector.hpp b/include/aare/ClusterVector.hpp index febf06c..1c15a22 100644 --- a/include/aare/ClusterVector.hpp +++ b/include/aare/ClusterVector.hpp @@ -231,6 +231,10 @@ template class ClusterVector { return *reinterpret_cast(element_ptr(i)); } + template const V &at(size_t i) const { + return *reinterpret_cast(element_ptr(i)); + } + const std::string_view fmt_base() const { // TODO! how do we match on coord_t? return m_fmt_base; diff --git a/include/aare/Interpolator.hpp b/include/aare/Interpolator.hpp new file mode 100644 index 0000000..4905bce --- /dev/null +++ b/include/aare/Interpolator.hpp @@ -0,0 +1,29 @@ +#pragma once +#include "aare/NDArray.hpp" +#include "aare/NDView.hpp" +#include "aare/ClusterVector.hpp" +#include "aare/ClusterFile.hpp" //Cluster_3x3 +namespace aare{ + +struct Photon{ + double x; + double y; + double energy; +}; + +class Interpolator{ + NDArray m_ietax; + NDArray m_ietay; + + NDArray m_etabinsx; + NDArray m_etabinsy; + NDArray m_energy_bins; + public: + Interpolator(NDView etacube, NDView xbins, NDView ybins, NDView ebins); + NDArray get_ietax(){return m_ietax;} + NDArray get_ietay(){return m_ietay;} + + std::vector interpolate(const ClusterVector& clusters); +}; + +} // namespace aare \ No newline at end of file diff --git a/python/aare/__init__.py b/python/aare/__init__.py index f4c19cc..41deb6c 100644 --- a/python/aare/__init__.py +++ b/python/aare/__init__.py @@ -7,6 +7,7 @@ from ._aare import Pedestal_d, Pedestal_f, ClusterFinder, VarClusterFinder from ._aare import DetectorType from ._aare import ClusterFile from ._aare import hitmap +from ._aare import ROI from ._aare import ClusterFinderMT, ClusterCollector, ClusterFileSink, ClusterVector_i diff --git a/python/examples/play.py b/python/examples/play.py index 37754df..05f3c82 100644 --- a/python/examples/play.py +++ b/python/examples/play.py @@ -1,50 +1,40 @@ import sys sys.path.append('/home/l_msdetect/erik/aare/build') + #Our normal python imports from pathlib import Path import matplotlib.pyplot as plt +from mpl_toolkits.axes_grid1 import make_axes_locatable import numpy as np import boost_histogram as bh import time +import tifffile -import aare - -data = np.random.normal(10, 1, 1000) - -hist = bh.Histogram(bh.axis.Regular(10, 0, 20)) -hist.fill(data) +#Directly import what we need from aare +from aare import File, ClusterFile, hitmap +from aare._aare import calculate_eta2, ClusterFinderMT, ClusterCollector -x = hist.axes[0].centers -y = hist.values() -y_err = np.sqrt(y)+1 -res = aare.fit_gaus(x, y, y_err, chi2 = True) +base = Path('/mnt/sls_det_storage/moench_data/tomcat_nanoscope_21042020/09_Moench_650um/') +# for f in base.glob('*'): +# print(f.name) - -t_elapsed = time.perf_counter()-t0 -print(f'Histogram filling took: {t_elapsed:.3f}s {total_clusters/t_elapsed/1e6:.3f}M clusters/s') +cluster_fname = base/'acq_interp_center_3.8Mfr_200V.clust' +flatfield_fname = base/'flatfield_center_200_d0_f000000000000_0.clust' -histogram_data = hist3d.counts() -x = hist3d.axes[2].edges[:-1] - -y = histogram_data[100,100,:] -xx = np.linspace(x[0], x[-1]) -# fig, ax = plt.subplots() -# ax.step(x, y, where = 'post') - -y_err = np.sqrt(y) -y_err = np.zeros(y.size) -y_err += 1 - -# par = fit_gaus2(y,x, y_err) -# ax.plot(xx, gaus(xx,par)) -# print(par) - -res = fit_gaus(y,x) -res2 = fit_gaus(y,x, y_err) -print(res) -print(res2) +cluster_fname.stat().st_size/1e6/4 +image = np.zeros((400,400)) +with ClusterFile(cluster_fname, chunk_size = 1000000) as f: + for clusters in f: + test = hitmap(image.shape, clusters) + break + # image += hitmap(image.shape, clusters) + # break +print('We are back in python') +# fig, ax = plt.subplots(figsize = (7,7)) +# im = ax.imshow(image) +# im.set_clim(0,1) \ No newline at end of file diff --git a/python/src/aare.code-workspace b/python/src/aare.code-workspace new file mode 100644 index 0000000..01045a6 --- /dev/null +++ b/python/src/aare.code-workspace @@ -0,0 +1,98 @@ +{ + "folders": [ + { + "path": "../../.." + }, + { + "path": "../../../../slsDetectorPackage" + } + ], + "settings": { + "files.associations": { + "compare": "cpp", + "cstdint": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "csignal": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "any": "cpp", + "array": "cpp", + "atomic": "cpp", + "strstream": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "bitset": "cpp", + "cfenv": "cpp", + "charconv": "cpp", + "chrono": "cpp", + "codecvt": "cpp", + "complex": "cpp", + "concepts": "cpp", + "condition_variable": "cpp", + "deque": "cpp", + "forward_list": "cpp", + "list": "cpp", + "map": "cpp", + "set": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "ratio": "cpp", + "source_location": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "format": "cpp", + "fstream": "cpp", + "future": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "numbers": "cpp", + "ostream": "cpp", + "ranges": "cpp", + "semaphore": "cpp", + "shared_mutex": "cpp", + "span": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "stdfloat": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "text_encoding": "cpp", + "thread": "cpp", + "cinttypes": "cpp", + "typeindex": "cpp", + "typeinfo": "cpp", + "valarray": "cpp", + "variant": "cpp", + "regex": "cpp", + "*.ipp": "cpp" + } + } +} \ No newline at end of file diff --git a/python/src/cluster.hpp b/python/src/cluster.hpp index 792b7e6..3db816a 100644 --- a/python/src/cluster.hpp +++ b/python/src/cluster.hpp @@ -20,7 +20,13 @@ template void define_cluster_vector(py::module &m, const std::string &typestr) { auto class_name = fmt::format("ClusterVector_{}", typestr); py::class_>(m, class_name.c_str(), py::buffer_protocol()) - .def(py::init()) + .def(py::init(), + py::arg("cluster_size_x") = 3, py::arg("cluster_size_y") = 3) + .def("push_back", + [](ClusterVector &self, int x, int y, py::array_t data) { + // auto view = make_view_2d(data); + self.push_back(x, y, reinterpret_cast(data.data())); + }) .def_property_readonly("size", &ClusterVector::size) .def("item_size", &ClusterVector::item_size) .def_property_readonly("fmt", @@ -38,6 +44,8 @@ void define_cluster_vector(py::module &m, const std::string &typestr) { auto *vec = new std::vector(self.sum_2x2()); return return_vector(vec); }) + .def_property_readonly("cluster_size_x", &ClusterVector::cluster_size_x) + .def_property_readonly("cluster_size_y", &ClusterVector::cluster_size_y) .def_property_readonly("capacity", &ClusterVector::capacity) .def_property("frame_number", &ClusterVector::frame_number, &ClusterVector::set_frame_number) diff --git a/python/src/cluster_file.hpp b/python/src/cluster_file.hpp index 8a431b5..f587443 100644 --- a/python/src/cluster_file.hpp +++ b/python/src/cluster_file.hpp @@ -31,6 +31,11 @@ void define_cluster_file_io_bindings(py::module &m) { auto v = new ClusterVector(self.read_clusters(n_clusters)); return v; },py::return_value_policy::take_ownership) + .def("read_clusters", + [](ClusterFile &self, size_t n_clusters, ROI roi) { + auto v = new ClusterVector(self.read_clusters(n_clusters, roi)); + return v; + },py::return_value_policy::take_ownership) .def("read_frame", [](ClusterFile &self) { auto v = new ClusterVector(self.read_frame()); diff --git a/python/src/file.hpp b/python/src/file.hpp index c3c800c..0d64e16 100644 --- a/python/src/file.hpp +++ b/python/src/file.hpp @@ -195,6 +195,8 @@ void define_file_io_bindings(py::module &m) { py::class_(m, "ROI") .def(py::init<>()) + .def(py::init(), py::arg("xmin"), + py::arg("xmax"), py::arg("ymin"), py::arg("ymax")) .def_readwrite("xmin", &ROI::xmin) .def_readwrite("xmax", &ROI::xmax) .def_readwrite("ymin", &ROI::ymin) diff --git a/python/src/interpolation.hpp b/python/src/interpolation.hpp new file mode 100644 index 0000000..02742e1 --- /dev/null +++ b/python/src/interpolation.hpp @@ -0,0 +1,58 @@ +#include "aare/Interpolator.hpp" +#include "aare/NDArray.hpp" +#include "aare/NDView.hpp" +#include "np_helper.hpp" +#include +#include +#include +#include + +namespace py = pybind11; +void define_interpolation_bindings(py::module &m) { + + PYBIND11_NUMPY_DTYPE(aare::Photon, x,y,energy); + + py::class_(m, "Interpolator") + .def(py::init([](py::array_t etacube, py::array_t xbins, + py::array_t ybins, py::array_t ebins) { + return Interpolator(make_view_3d(etacube), make_view_1d(xbins), + make_view_1d(ybins), make_view_1d(ebins)); + })) + .def("get_ietax", [](Interpolator& self){ + auto*ptr = new NDArray{}; + *ptr = self.get_ietax(); + return return_image_data(ptr); + }) + .def("get_ietay", [](Interpolator& self){ + auto*ptr = new NDArray{}; + *ptr = self.get_ietay(); + return return_image_data(ptr); + }) + .def("interpolate", [](Interpolator& self, const ClusterVector& clusters){ + auto photons = self.interpolate(clusters); + auto* ptr = new std::vector{photons}; + return return_vector(ptr); + }); + + // TODO! Evaluate without converting to double + m.def( + "hej", + []() { + // auto boost_histogram = py::module_::import("boost_histogram"); + // py::object axis = + // boost_histogram.attr("axis").attr("Regular")(10, 0.0, 10.0); + // py::object histogram = boost_histogram.attr("Histogram")(axis); + // return histogram; + // return h; + }, + R"( + Evaluate a 1D Gaussian function for all points in x using parameters par. + + Parameters + ---------- + x : array_like + The points at which to evaluate the Gaussian function. + par : array_like + The parameters of the Gaussian function. The first element is the amplitude, the second element is the mean, and the third element is the standard deviation. + )"); +} \ No newline at end of file diff --git a/python/src/module.cpp b/python/src/module.cpp index 70d143f..43f48ba 100644 --- a/python/src/module.cpp +++ b/python/src/module.cpp @@ -9,6 +9,7 @@ #include "cluster.hpp" #include "cluster_file.hpp" #include "fit.hpp" +#include "interpolation.hpp" //Pybind stuff #include @@ -31,5 +32,6 @@ PYBIND11_MODULE(_aare, m) { define_cluster_collector_bindings(m); define_cluster_file_sink_bindings(m); define_fit_bindings(m); + define_interpolation_bindings(m); } \ No newline at end of file diff --git a/src/ClusterFile.cpp b/src/ClusterFile.cpp index 2928d26..37b5e89 100644 --- a/src/ClusterFile.cpp +++ b/src/ClusterFile.cpp @@ -108,6 +108,79 @@ ClusterVector ClusterFile::read_clusters(size_t n_clusters) { return clusters; } +ClusterVector ClusterFile::read_clusters(size_t n_clusters, ROI roi) { + if (m_mode != "r") { + throw std::runtime_error("File not opened for reading"); + } + + ClusterVector clusters(3,3); + clusters.reserve(n_clusters); + + int32_t iframe = 0; // frame number needs to be 4 bytes! + size_t nph_read = 0; + uint32_t nn = m_num_left; + uint32_t nph = m_num_left; // number of clusters in frame needs to be 4 + + // auto buf = reinterpret_cast(clusters.data()); + // auto buf = clusters.data(); + + Cluster3x3 tmp; //this would break if the cluster size changes + + // if there are photons left from previous frame read them first + if (nph) { + if (nph > n_clusters) { + // if we have more photons left in the frame then photons to read we + // read directly the requested number + nn = n_clusters; + } else { + nn = nph; + } + //Read one cluster, in the ROI push back + // nph_read += fread((buf + nph_read*clusters.item_size()), + // clusters.item_size(), nn, fp); + for(size_t i = 0; i < nn; i++){ + fread(&tmp, sizeof(tmp), 1, fp); + if(tmp.x >= roi.xmin && tmp.x <= roi.xmax && tmp.y >= roi.ymin && tmp.y <= roi.ymax){ + clusters.push_back(tmp.x, tmp.y, reinterpret_cast(tmp.data)); + nph_read++; + } + } + + m_num_left = nph - nn; // write back the number of photons left + } + + if (nph_read < n_clusters) { + // keep on reading frames and photons until reaching n_clusters + while (fread(&iframe, sizeof(iframe), 1, fp)) { + // read number of clusters in frame + if (fread(&nph, sizeof(nph), 1, fp)) { + if (nph > (n_clusters - nph_read)) + nn = n_clusters - nph_read; + else + nn = nph; + + // nph_read += fread((buf + nph_read*clusters.item_size()), + // clusters.item_size(), nn, fp); + for(size_t i = 0; i < nn; i++){ + fread(&tmp, sizeof(tmp), 1, fp); + if(tmp.x >= roi.xmin && tmp.x <= roi.xmax && tmp.y >= roi.ymin && tmp.y <= roi.ymax){ + clusters.push_back(tmp.x, tmp.y, reinterpret_cast(tmp.data)); + nph_read++; + } + } + m_num_left = nph - nn; + } + if (nph_read >= n_clusters) + break; + } + } + + // Resize the vector to the number of clusters. + // No new allocation, only change bounds. + clusters.resize(nph_read); + return clusters; +} + ClusterVector ClusterFile::read_frame() { if (m_mode != "r") { throw std::runtime_error("File not opened for reading"); @@ -268,11 +341,23 @@ ClusterVector ClusterFile::read_frame() { NDArray calculate_eta2(ClusterVector &clusters) { //TOTO! make work with 2x2 clusters NDArray eta2({static_cast(clusters.size()), 2}); - for (size_t i = 0; i < clusters.size(); i++) { - auto e = calculate_eta2(clusters.at(i)); - eta2(i, 0) = e.x; - eta2(i, 1) = e.y; + + if (clusters.cluster_size_x() == 3 || clusters.cluster_size_y() == 3) { + for (size_t i = 0; i < clusters.size(); i++) { + auto e = calculate_eta2(clusters.at(i)); + eta2(i, 0) = e.x; + eta2(i, 1) = e.y; + } + }else if(clusters.cluster_size_x() == 2 || clusters.cluster_size_y() == 2){ + for (size_t i = 0; i < clusters.size(); i++) { + auto e = calculate_eta2(clusters.at(i)); + eta2(i, 0) = e.x; + eta2(i, 1) = e.y; + } + }else{ + throw std::runtime_error("Only 3x3 and 2x2 clusters are supported"); } + return eta2; } @@ -290,7 +375,7 @@ Eta2 calculate_eta2(Cluster3x3 &cl) { tot2[3] = cl.data[4] + cl.data[5] + cl.data[7] + cl.data[8]; auto c = std::max_element(tot2.begin(), tot2.end()) - tot2.begin(); - + eta.sum = tot2[c]; switch (c) { case cBottomLeft: if ((cl.data[3] + cl.data[4]) != 0) @@ -333,6 +418,19 @@ Eta2 calculate_eta2(Cluster3x3 &cl) { return eta; } + +Eta2 calculate_eta2(Cluster2x2 &cl) { + Eta2 eta{}; + + eta.x = static_cast(cl.data[0]) / (cl.data[0] + cl.data[1]); + eta.y = static_cast(cl.data[0]) / (cl.data[0] + cl.data[2]); + eta.sum = cl.data[0] + cl.data[1] + cl.data[2]+ cl.data[3]; + eta.c = cBottomLeft; //TODO! This is not correct + return eta; +} + + + int analyze_cluster(Cluster3x3 &cl, int32_t *t2, int32_t *t3, char *quad, double *eta2x, double *eta2y, double *eta3x, double *eta3y) { diff --git a/src/Interpolator.cpp b/src/Interpolator.cpp new file mode 100644 index 0000000..a4ecb94 --- /dev/null +++ b/src/Interpolator.cpp @@ -0,0 +1,159 @@ +#include "aare/Interpolator.hpp" + +namespace aare { + +Interpolator::Interpolator(NDView etacube, NDView xbins, + NDView ybins, NDView ebins) + : m_ietax(etacube), m_ietay(etacube), m_etabinsx(xbins), m_etabinsy(ybins), m_energy_bins(ebins) { + if (etacube.shape(0) != xbins.size() || etacube.shape(1) != ybins.size() || + etacube.shape(2) != ebins.size()) { + throw std::invalid_argument( + "The shape of the etacube does not match the shape of the bins"); + } + + // Cumulative sum in the x direction, can maybe be combined with a copy? + for (ssize_t k = 0; k < m_ietax.shape(2); k++) { + for (ssize_t j = 0; j < m_ietax.shape(1); j++) { + for (ssize_t i = 1; i < m_ietax.shape(0); i++) { + m_ietax(i, j, k) += m_ietax(i - 1, j, k); + } + } + } + + // Normalize by the highest row, if norm less than 1 don't do anything + for (ssize_t k = 0; k < m_ietax.shape(2); k++) { + for (ssize_t j = 0; j < m_ietax.shape(1); j++) { + auto val = m_ietax(m_ietax.shape(0) - 1, j, k); + double norm = val < 1 ? 1 : val; + for (ssize_t i = 0; i < m_ietax.shape(0); i++) { + m_ietax(i, j, k) /= norm; + } + } + } + + // Cumulative sum in the y direction + for (ssize_t k = 0; k < m_ietay.shape(2); k++) { + for (ssize_t i = 0; i < m_ietay.shape(0); i++) { + for (ssize_t j = 1; j < m_ietay.shape(1); j++) { + m_ietay(i, j, k) += m_ietay(i, j - 1, k); + } + } + } + + // Normalize by the highest column, if norm less than 1 don't do anything + for (ssize_t k = 0; k < m_ietay.shape(2); k++) { + for (ssize_t i = 0; i < m_ietay.shape(0); i++) { + auto val = m_ietay(i, m_ietay.shape(1) - 1, k); + double norm = val < 1 ? 1 : val; + for (ssize_t j = 0; j < m_ietay.shape(1); j++) { + m_ietay(i, j, k) /= norm; + } + } + } + +} + +std::vector Interpolator::interpolate(const ClusterVector& clusters) { + std::vector photons; + photons.reserve(clusters.size()); + + if (clusters.cluster_size_x() == 3 || clusters.cluster_size_y() == 3) { + for (size_t i = 0; i(i); + Eta2 eta= calculate_eta2(cluster); + + Photon photon; + photon.x = cluster.x; + photon.y = cluster.y; + photon.energy = eta.sum; + + //Now do some actual interpolation. + //Find which energy bin the cluster is in + //TODO! Could we use boost-histogram Axis.index here? + ssize_t idx = std::lower_bound(m_energy_bins.begin(), m_energy_bins.end(), photon.energy)-m_energy_bins.begin(); + auto ix = std::lower_bound(m_etabinsx.begin(), m_etabinsx.end(), eta.x)- m_etabinsx.begin(); + auto iy = std::lower_bound(m_etabinsy.begin(), m_etabinsy.end(), eta.y)- m_etabinsy.begin(); + + + // ibx=(np.abs(etabinsx - ex)).argmin() #Find out which bin the eta should land in + // iby=(np.abs(etabinsy - ey)).argmin() + double dX, dY; + int ex, ey; + // cBottomLeft = 0, + // cBottomRight = 1, + // cTopLeft = 2, + // cTopRight = 3 + switch (eta.c) { + case cTopLeft: + dX = -1.; + dY = 0; + break; + case cTopRight:; + dX = 0; + dY = 0; + break; + case cBottomLeft: + dX = -1.; + dY = -1.; + break; + case cBottomRight: + dX = 0; + dY = -1.; + break; + } + photon.x += m_ietax(ix, iy, idx) + dX + 0.5; + photon.y += m_ietay(ix, iy, idx) + dY + 0.5; + + + // fmt::print("x: {}, y: {}, energy: {}\n", photon.x, photon.y, photon.energy); + photons.push_back(photon); + } + }else if(clusters.cluster_size_x() == 2 || clusters.cluster_size_y() == 2){ + //TODO! Implement 2x2 interpolation + for (size_t i = 0; i(i); + Eta2 eta= calculate_eta2(cluster); + + Photon photon; + photon.x = cluster.x; + photon.y = cluster.y; + photon.energy = eta.sum; + + //Now do some actual interpolation. + //Find which energy bin the cluster is in + //TODO! Could we use boost-histogram Axis.index here? + ssize_t idx = std::lower_bound(m_energy_bins.begin(), m_energy_bins.end(), photon.energy)-m_energy_bins.begin(); + // auto ix = std::lower_bound(m_etabinsx.begin(), m_etabinsx.end(), eta.x)- m_etabinsx.begin(); + // auto iy = std::lower_bound(m_etabinsy.begin(), m_etabinsy.end(), eta.y)- m_etabinsy.begin(); + // if(ix<0) ix=0; + // if(iy<0) iy=0; + + auto find_index = [](NDArray& etabins, double val){ + auto iter = std::min_element(etabins.begin(), etabins.end(), + [val,etabins](double a, double b) { + return std::abs(a - val) < std::abs(b - val); + }); + return std::distance(etabins.begin(), iter); + }; + auto ix = find_index(m_etabinsx, eta.x)-1; + auto iy = find_index(m_etabinsy, eta.y)-1; + + photon.x += (1-m_ietax(ix, iy, idx))*2; //eta goes between 0 and 1 but we could move the hit anywhere in the 2x2 + photon.y += (1-m_ietay(ix, iy, idx))*2; + + // photon.x = ix; + // photon.y = iy; + photons.push_back(photon); + } + + }else{ + throw std::runtime_error("Only 3x3 and 2x2 clusters are supported for interpolation"); + } + + + return photons; +} + +} // namespace aare \ No newline at end of file diff --git a/src/NDArray.test.cpp b/src/NDArray.test.cpp index 942481c..eff3e2c 100644 --- a/src/NDArray.test.cpp +++ b/src/NDArray.test.cpp @@ -2,6 +2,7 @@ #include #include #include +#include using aare::NDArray; using aare::NDView; @@ -34,6 +35,24 @@ TEST_CASE("Construct from an NDView") { } } +TEST_CASE("3D NDArray from NDView"){ + std::vector data(27); + std::iota(data.begin(), data.end(), 0); + NDView view(data.data(), Shape<3>{3, 3, 3}); + NDArray image(view); + REQUIRE(image.shape() == view.shape()); + REQUIRE(image.size() == view.size()); + REQUIRE(image.data() != view.data()); + + for(int64_t i=0; i shape{{20}}; NDArray img(shape, 3); From 3a987319d4f2233942e994f61f13f9b28c2773fa Mon Sep 17 00:00:00 2001 From: froejdh_e Date: Wed, 5 Mar 2025 21:51:23 +0100 Subject: [PATCH 02/51] WIP --- src/ClusterFile.cpp | 6 +++--- src/Interpolator.cpp | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/ClusterFile.cpp b/src/ClusterFile.cpp index 37b5e89..be3f607 100644 --- a/src/ClusterFile.cpp +++ b/src/ClusterFile.cpp @@ -422,10 +422,10 @@ Eta2 calculate_eta2(Cluster3x3 &cl) { Eta2 calculate_eta2(Cluster2x2 &cl) { Eta2 eta{}; - eta.x = static_cast(cl.data[0]) / (cl.data[0] + cl.data[1]); - eta.y = static_cast(cl.data[0]) / (cl.data[0] + cl.data[2]); + eta.x = static_cast(cl.data[1]) / (cl.data[0] + cl.data[1]); + eta.y = static_cast(cl.data[2]) / (cl.data[0] + cl.data[2]); eta.sum = cl.data[0] + cl.data[1] + cl.data[2]+ cl.data[3]; - eta.c = cBottomLeft; //TODO! This is not correct + eta.c = cBottomLeft; //TODO! This is not correct, but need to put something return eta; } diff --git a/src/Interpolator.cpp b/src/Interpolator.cpp index a4ecb94..0e72849 100644 --- a/src/Interpolator.cpp +++ b/src/Interpolator.cpp @@ -139,12 +139,14 @@ std::vector Interpolator::interpolate(const ClusterVector& clus }; auto ix = find_index(m_etabinsx, eta.x)-1; auto iy = find_index(m_etabinsy, eta.y)-1; + if(ix<0) ix=0; + if(iy<0) iy=0; - photon.x += (1-m_ietax(ix, iy, idx))*2; //eta goes between 0 and 1 but we could move the hit anywhere in the 2x2 - photon.y += (1-m_ietay(ix, iy, idx))*2; + photon.x += m_ietax(ix, iy, 0)*2; //eta goes between 0 and 1 but we could move the hit anywhere in the 2x2 + photon.y += m_ietay(ix, iy, 0)*2; // photon.x = ix; - // photon.y = iy; + // photon.y = idx; photons.push_back(photon); } From 332bdeb02ba5ac03fa37fe30b114fb7db1556ba4 Mon Sep 17 00:00:00 2001 From: froejdh_e Date: Fri, 14 Mar 2025 11:07:09 +0100 Subject: [PATCH 03/51] modified algo --- CMakeLists.txt | 1 + include/aare/NDArray.hpp | 3 ++ include/aare/algorithm.hpp | 55 ++++++++++++++++++++++++ python/examples/play.py | 87 +++++++++++++++++++++++++++----------- src/Interpolator.cpp | 60 ++++++++++---------------- src/algorithm.test.cpp | 63 +++++++++++++++++++++++++++ 6 files changed, 206 insertions(+), 63 deletions(-) create mode 100644 include/aare/algorithm.hpp create mode 100644 src/algorithm.test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index bff2afe..4772f0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -386,6 +386,7 @@ endif() if(AARE_TESTS) set(TestSources + ${CMAKE_CURRENT_SOURCE_DIR}/src/algorithm.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/defs.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Dtype.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Frame.test.cpp diff --git a/include/aare/NDArray.hpp b/include/aare/NDArray.hpp index 310d070..45d3a83 100644 --- a/include/aare/NDArray.hpp +++ b/include/aare/NDArray.hpp @@ -102,6 +102,9 @@ class NDArray : public ArrayExpr, Ndim> { auto begin() { return data_; } auto end() { return data_ + size_; } + auto begin() const { return data_; } + auto end() const { return data_ + size_; } + using value_type = T; NDArray &operator=(NDArray &&other) noexcept; // Move assign diff --git a/include/aare/algorithm.hpp b/include/aare/algorithm.hpp new file mode 100644 index 0000000..5d6dc57 --- /dev/null +++ b/include/aare/algorithm.hpp @@ -0,0 +1,55 @@ + +#pragma once +#include +#include +#include +#include + +namespace aare { +/** + * @brief Find the index of the last element smaller than val + * assume a sorted array + */ +template +size_t last_smaller(const T* first, const T* last, T val) { + for (auto iter = first+1; iter != last; ++iter) { + if (*iter > val) { + return std::distance(first, iter-1); + } + } + return std::distance(first, last-1); +} + +template +size_t last_smaller(const NDArray& arr, T val) { + return last_smaller(arr.begin(), arr.end(), val); +} + + +template +size_t nearest_index(const T* first, const T* last, T val) { + auto iter = std::min_element(first, last, + [val](T a, T b) { + return std::abs(a - val) < std::abs(b - val); + }); + return std::distance(first, iter); +} + +template +size_t nearest_index(const NDArray& arr, T val) { + return nearest_index(arr.begin(), arr.end(), val); +} + +template +size_t nearest_index(const std::vector& vec, T val) { + return nearest_index(vec.data(), vec.data()+vec.size(), val); +} + +template +size_t nearest_index(const std::array& arr, T val) { + return nearest_index(arr.data(), arr.data()+arr.size(), val); +} + + + +} // namespace aare \ No newline at end of file diff --git a/python/examples/play.py b/python/examples/play.py index 05f3c82..b2c368b 100644 --- a/python/examples/play.py +++ b/python/examples/play.py @@ -1,40 +1,77 @@ import sys sys.path.append('/home/l_msdetect/erik/aare/build') +from aare._aare import ClusterVector_i, Interpolator -#Our normal python imports -from pathlib import Path -import matplotlib.pyplot as plt -from mpl_toolkits.axes_grid1 import make_axes_locatable +import pickle import numpy as np +import matplotlib.pyplot as plt import boost_histogram as bh +import torch +import math import time -import tifffile -#Directly import what we need from aare -from aare import File, ClusterFile, hitmap -from aare._aare import calculate_eta2, ClusterFinderMT, ClusterCollector +def gaussian_2d(mx, my, sigma = 1, res=100, grid_size = 2): + """ + Generate a 2D gaussian as position mx, my, with sigma=sigma. + The gaussian is placed on a 2x2 pixel matrix with resolution + res in one dimesion. + """ + x = torch.linspace(0, pixel_size*grid_size, res) + x,y = torch.meshgrid(x,x, indexing="ij") + return 1 / (2*math.pi*sigma**2) * \ + torch.exp(-((x - my)**2 / (2*sigma**2) + (y - mx)**2 / (2*sigma**2))) + +scale = 1000 #Scale factor when converting to integer +pixel_size = 25 #um +grid = 2 +resolution = 100 +sigma_um = 10 +xa = np.linspace(0,grid*pixel_size,resolution) +ticks = [0, 25, 50] + +hit = np.array((20,20)) +etahist_fname = "/home/l_msdetect/erik/tmp/test_hist.pkl" + +local_resolution = 99 +grid_size = 3 +xaxis = np.linspace(0,grid_size*pixel_size, local_resolution) +t = gaussian_2d(hit[0],hit[1], grid_size = grid_size, sigma = 10, res = local_resolution) +pixels = t.reshape(grid_size, t.shape[0] // grid_size, grid_size, t.shape[1] // grid_size).sum(axis = 3).sum(axis = 1) +pixels = pixels.numpy() +pixels = (pixels*scale).astype(np.int32) +v = ClusterVector_i(3,3) +v.push_back(1,1, pixels) + +with open(etahist_fname, "rb") as f: + hist = pickle.load(f) +eta = hist.view().copy() +etabinsx = np.array(hist.axes.edges.T[0].flat) +etabinsy = np.array(hist.axes.edges.T[1].flat) +ebins = np.array(hist.axes.edges.T[2].flat) +p = Interpolator(eta, etabinsx[0:-1], etabinsy[0:-1], ebins[0:-1]) -base = Path('/mnt/sls_det_storage/moench_data/tomcat_nanoscope_21042020/09_Moench_650um/') -# for f in base.glob('*'): -# print(f.name) +#Generate the hit -cluster_fname = base/'acq_interp_center_3.8Mfr_200V.clust' -flatfield_fname = base/'flatfield_center_200_d0_f000000000000_0.clust' -cluster_fname.stat().st_size/1e6/4 -image = np.zeros((400,400)) -with ClusterFile(cluster_fname, chunk_size = 1000000) as f: - for clusters in f: - test = hitmap(image.shape, clusters) - break - # image += hitmap(image.shape, clusters) - # break -print('We are back in python') -# fig, ax = plt.subplots(figsize = (7,7)) -# im = ax.imshow(image) -# im.set_clim(0,1) \ No newline at end of file + +tmp = p.interpolate(v) +print(f'tmp:{tmp}') +pos = np.array((tmp['x'], tmp['y']))*25 + + +print(pixels) +fig, ax = plt.subplots(figsize = (7,7)) +ax.pcolormesh(xaxis, xaxis, t) +ax.plot(*pos, 'o') +ax.set_xticks([0,25,50,75]) +ax.set_yticks([0,25,50,75]) +ax.set_xlim(0,75) +ax.set_ylim(0,75) +ax.grid() +print(f'{hit=}') +print(f'{pos=}') \ No newline at end of file diff --git a/src/Interpolator.cpp b/src/Interpolator.cpp index 0e72849..85e0b5d 100644 --- a/src/Interpolator.cpp +++ b/src/Interpolator.cpp @@ -1,4 +1,5 @@ #include "aare/Interpolator.hpp" +#include "aare/algorithm.hpp" namespace aare { @@ -68,16 +69,17 @@ std::vector Interpolator::interpolate(const ClusterVector& clus photon.y = cluster.y; photon.energy = eta.sum; - //Now do some actual interpolation. - //Find which energy bin the cluster is in - //TODO! Could we use boost-histogram Axis.index here? - ssize_t idx = std::lower_bound(m_energy_bins.begin(), m_energy_bins.end(), photon.energy)-m_energy_bins.begin(); - auto ix = std::lower_bound(m_etabinsx.begin(), m_etabinsx.end(), eta.x)- m_etabinsx.begin(); - auto iy = std::lower_bound(m_etabinsy.begin(), m_etabinsy.end(), eta.y)- m_etabinsy.begin(); - + // auto ie = nearest_index(m_energy_bins, photon.energy)-1; + // auto ix = nearest_index(m_etabinsx, eta.x)-1; + // auto iy = nearest_index(m_etabinsy, eta.y)-1; + //Finding the index of the last element that is smaller + //should work fine as long as we have many bins + auto ie = last_smaller(m_energy_bins, photon.energy); + auto ix = last_smaller(m_etabinsx, eta.x); + auto iy = last_smaller(m_etabinsy, eta.y); + + // fmt::print("ex: {}, ix: {}, iy: {}\n", ie, ix, iy); - // ibx=(np.abs(etabinsx - ex)).argmin() #Find out which bin the eta should land in - // iby=(np.abs(etabinsy - ey)).argmin() double dX, dY; int ex, ey; // cBottomLeft = 0, @@ -98,21 +100,16 @@ std::vector Interpolator::interpolate(const ClusterVector& clus dY = -1.; break; case cBottomRight: - dX = 0; + dX = 0.; dY = -1.; break; } - photon.x += m_ietax(ix, iy, idx) + dX + 0.5; - photon.y += m_ietay(ix, iy, idx) + dY + 0.5; - - - // fmt::print("x: {}, y: {}, energy: {}\n", photon.x, photon.y, photon.energy); + photon.x += m_ietax(ix, iy, 0)*2 + dX; + photon.y += m_ietay(ix, iy, 0)*2 + dY; photons.push_back(photon); } }else if(clusters.cluster_size_x() == 2 || clusters.cluster_size_y() == 2){ - //TODO! Implement 2x2 interpolation for (size_t i = 0; i(i); Eta2 eta= calculate_eta2(cluster); @@ -123,30 +120,17 @@ std::vector Interpolator::interpolate(const ClusterVector& clus //Now do some actual interpolation. //Find which energy bin the cluster is in - //TODO! Could we use boost-histogram Axis.index here? - ssize_t idx = std::lower_bound(m_energy_bins.begin(), m_energy_bins.end(), photon.energy)-m_energy_bins.begin(); - // auto ix = std::lower_bound(m_etabinsx.begin(), m_etabinsx.end(), eta.x)- m_etabinsx.begin(); - // auto iy = std::lower_bound(m_etabinsy.begin(), m_etabinsy.end(), eta.y)- m_etabinsy.begin(); - // if(ix<0) ix=0; - // if(iy<0) iy=0; - - auto find_index = [](NDArray& etabins, double val){ - auto iter = std::min_element(etabins.begin(), etabins.end(), - [val,etabins](double a, double b) { - return std::abs(a - val) < std::abs(b - val); - }); - return std::distance(etabins.begin(), iter); - }; - auto ix = find_index(m_etabinsx, eta.x)-1; - auto iy = find_index(m_etabinsy, eta.y)-1; - if(ix<0) ix=0; - if(iy<0) iy=0; + // auto ie = nearest_index(m_energy_bins, photon.energy)-1; + // auto ix = nearest_index(m_etabinsx, eta.x)-1; + // auto iy = nearest_index(m_etabinsy, eta.y)-1; + //Finding the index of the last element that is smaller + //should work fine as long as we have many bins + auto ie = last_smaller(m_energy_bins, photon.energy); + auto ix = last_smaller(m_etabinsx, eta.x); + auto iy = last_smaller(m_etabinsy, eta.y); photon.x += m_ietax(ix, iy, 0)*2; //eta goes between 0 and 1 but we could move the hit anywhere in the 2x2 photon.y += m_ietay(ix, iy, 0)*2; - - // photon.x = ix; - // photon.y = idx; photons.push_back(photon); } diff --git a/src/algorithm.test.cpp b/src/algorithm.test.cpp new file mode 100644 index 0000000..9e75eb9 --- /dev/null +++ b/src/algorithm.test.cpp @@ -0,0 +1,63 @@ + + +#include +#include + + +TEST_CASE("Find the closed index in a 1D array", "[algorithm]") { + aare::NDArray arr({5}); + for (size_t i = 0; i < arr.size(); i++) { + arr[i] = i; + } + // arr 0, 1, 2, 3, 4 + REQUIRE(aare::nearest_index(arr, 2.3) == 2); + REQUIRE(aare::nearest_index(arr, 2.6) == 3); + REQUIRE(aare::nearest_index(arr, 45.0) == 4); + REQUIRE(aare::nearest_index(arr, 0.0) == 0); + REQUIRE(aare::nearest_index(arr, -1.0) == 0); +} + +TEST_CASE("Passing integers to nearest_index works"){ + aare::NDArray arr({5}); + for (size_t i = 0; i < arr.size(); i++) { + arr[i] = i; + } + // arr 0, 1, 2, 3, 4 + REQUIRE(aare::nearest_index(arr, 2) == 2); + REQUIRE(aare::nearest_index(arr, 3) == 3); + REQUIRE(aare::nearest_index(arr, 45) == 4); + REQUIRE(aare::nearest_index(arr, 0) == 0); + REQUIRE(aare::nearest_index(arr, -1) == 0); +} + + +TEST_CASE("nearest_index works with std::vector"){ + std::vector vec = {0, 1, 2, 3, 4}; + REQUIRE(aare::nearest_index(vec, 2.123) == 2); + REQUIRE(aare::nearest_index(vec, 2.66) == 3); + REQUIRE(aare::nearest_index(vec, 4555555.0) == 4); + REQUIRE(aare::nearest_index(vec, 0.0) == 0); + REQUIRE(aare::nearest_index(vec, -10.0) == 0); +} + +TEST_CASE("nearest index works with std::array"){ + std::array arr = {0, 1, 2, 3, 4}; + REQUIRE(aare::nearest_index(arr, 2.123) == 2); + REQUIRE(aare::nearest_index(arr, 2.501) == 3); + REQUIRE(aare::nearest_index(arr, 4555555.0) == 4); + REQUIRE(aare::nearest_index(arr, 0.0) == 0); + REQUIRE(aare::nearest_index(arr, -10.0) == 0); +} + + +TEST_CASE("last smaller"){ + aare::NDArray arr({5}); + for (size_t i = 0; i < arr.size(); i++) { + arr[i] = i; + } + // arr 0, 1, 2, 3, 4 + REQUIRE(aare::last_smaller(arr, -10.0) == 0); + REQUIRE(aare::last_smaller(arr, 0.0) == 0); + REQUIRE(aare::last_smaller(arr, 2.3) == 2); + REQUIRE(aare::last_smaller(arr, 253.) == 4); +} \ No newline at end of file From e59a361b513282d3091d8f2552f64ca9fa876050 Mon Sep 17 00:00:00 2001 From: froejdh_e Date: Mon, 17 Mar 2025 15:23:55 +0100 Subject: [PATCH 04/51] removed workspace --- python/src/aare.code-workspace | 98 ---------------------------------- 1 file changed, 98 deletions(-) delete mode 100644 python/src/aare.code-workspace diff --git a/python/src/aare.code-workspace b/python/src/aare.code-workspace deleted file mode 100644 index 01045a6..0000000 --- a/python/src/aare.code-workspace +++ /dev/null @@ -1,98 +0,0 @@ -{ - "folders": [ - { - "path": "../../.." - }, - { - "path": "../../../../slsDetectorPackage" - } - ], - "settings": { - "files.associations": { - "compare": "cpp", - "cstdint": "cpp", - "cctype": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "csignal": "cpp", - "cstdarg": "cpp", - "cstddef": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "ctime": "cpp", - "cwchar": "cpp", - "cwctype": "cpp", - "any": "cpp", - "array": "cpp", - "atomic": "cpp", - "strstream": "cpp", - "bit": "cpp", - "*.tcc": "cpp", - "bitset": "cpp", - "cfenv": "cpp", - "charconv": "cpp", - "chrono": "cpp", - "codecvt": "cpp", - "complex": "cpp", - "concepts": "cpp", - "condition_variable": "cpp", - "deque": "cpp", - "forward_list": "cpp", - "list": "cpp", - "map": "cpp", - "set": "cpp", - "string": "cpp", - "unordered_map": "cpp", - "unordered_set": "cpp", - "vector": "cpp", - "exception": "cpp", - "algorithm": "cpp", - "functional": "cpp", - "iterator": "cpp", - "memory": "cpp", - "memory_resource": "cpp", - "numeric": "cpp", - "optional": "cpp", - "random": "cpp", - "ratio": "cpp", - "source_location": "cpp", - "string_view": "cpp", - "system_error": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "utility": "cpp", - "format": "cpp", - "fstream": "cpp", - "future": "cpp", - "initializer_list": "cpp", - "iomanip": "cpp", - "iosfwd": "cpp", - "iostream": "cpp", - "istream": "cpp", - "limits": "cpp", - "mutex": "cpp", - "new": "cpp", - "numbers": "cpp", - "ostream": "cpp", - "ranges": "cpp", - "semaphore": "cpp", - "shared_mutex": "cpp", - "span": "cpp", - "sstream": "cpp", - "stdexcept": "cpp", - "stdfloat": "cpp", - "stop_token": "cpp", - "streambuf": "cpp", - "text_encoding": "cpp", - "thread": "cpp", - "cinttypes": "cpp", - "typeindex": "cpp", - "typeinfo": "cpp", - "valarray": "cpp", - "variant": "cpp", - "regex": "cpp", - "*.ipp": "cpp" - } - } -} \ No newline at end of file From 6e7e81b36ba7ab9276405df004c792d275111fe8 Mon Sep 17 00:00:00 2001 From: AliceMazzoleni99 Date: Fri, 21 Mar 2025 16:32:54 +0100 Subject: [PATCH 05/51] complete mess but need to install RedHat 9 --- include/aare/ClusterFile.hpp | 48 +++++---- include/aare/ClusterVector.hpp | 48 +++++---- src/ClusterFile.cpp | 184 ++++++++++++++++++++------------- 3 files changed, 162 insertions(+), 118 deletions(-) diff --git a/include/aare/ClusterFile.hpp b/include/aare/ClusterFile.hpp index 5bea342..d35f362 100644 --- a/include/aare/ClusterFile.hpp +++ b/include/aare/ClusterFile.hpp @@ -8,16 +8,12 @@ namespace aare { -//TODO! Template this? -struct Cluster3x3 { - int16_t x; - int16_t y; - int32_t data[9]; -}; -struct Cluster2x2 { - int16_t x; - int16_t y; - int32_t data[4]; +template +struct Cluster { + CoordType x; + CoordType y; + T data[ClusterSizeX * ClusterSizeY]; }; typedef enum { @@ -93,8 +89,7 @@ class ClusterFile { */ ClusterFile(const std::filesystem::path &fname, size_t chunk_size = 1000, const std::string &mode = "r"); - - + ~ClusterFile(); /** @@ -109,26 +104,26 @@ class ClusterFile { /** * @brief Read a single frame from the file and return the clusters. The * cluster vector will have the frame number set. - * @throws std::runtime_error if the file is not opened for reading or the file pointer not - * at the beginning of a frame + * @throws std::runtime_error if the file is not opened for reading or the + * file pointer not at the beginning of a frame */ ClusterVector read_frame(); - void write_frame(const ClusterVector &clusters); - + // Need to be migrated to support NDArray and return a ClusterVector // std::vector - // read_cluster_with_cut(size_t n_clusters, double *noise_map, int nx, int ny); + // read_cluster_with_cut(size_t n_clusters, double *noise_map, int nx, int + // ny); /** * @brief Return the chunk size */ size_t chunk_size() const { return m_chunk_size; } - - + /** - * @brief Close the file. If not closed the file will be closed in the destructor + * @brief Close the file. If not closed the file will be closed in the + * destructor */ void close(); }; @@ -138,8 +133,17 @@ int analyze_data(int32_t *data, int32_t *t2, int32_t *t3, char *quad, int analyze_cluster(Cluster3x3 &cl, int32_t *t2, int32_t *t3, char *quad, double *eta2x, double *eta2y, double *eta3x, double *eta3y); -NDArray calculate_eta2(ClusterVector &clusters); -Eta2 calculate_eta2(Cluster3x3 &cl); +template +NDArray calculate_eta2(ClusterVector &clusters); + +template Eta2 calculate_eta2(Cluster &cl); + Eta2 calculate_eta2(Cluster2x2 &cl); +template Eta2 calculate_eta2(ClusterType &cl); + +template +Eta2 calculate_eta2(Cluster &cl); + } // namespace aare diff --git a/include/aare/ClusterVector.hpp b/include/aare/ClusterVector.hpp index 1c15a22..c5e66b7 100644 --- a/include/aare/ClusterVector.hpp +++ b/include/aare/ClusterVector.hpp @@ -10,6 +10,8 @@ namespace aare { +template class ClusterVector; // Forward declaration + /** * @brief ClusterVector is a container for clusters of various sizes. It uses a * contiguous memory buffer to store the clusters. It is templated on the data @@ -21,10 +23,12 @@ namespace aare { * @tparam CoordType data type of the x and y coordinates of the cluster * (normally int16_t) */ -template class ClusterVector { +template +class ClusterVector> { using value_type = T; - size_t m_cluster_size_x; - size_t m_cluster_size_y; + // size_t m_cluster_size_x; + // size_t m_cluster_size_y; std::byte *m_data{}; size_t m_size{0}; size_t m_capacity; @@ -40,6 +44,8 @@ template class ClusterVector { constexpr static char m_fmt_base[] = "=h:x:\nh:y:\n({},{}){}:data:"; public: + using ClusterType = Cluster; + /** * @brief Construct a new ClusterVector object * @param cluster_size_x size of the cluster in x direction @@ -48,10 +54,8 @@ template class ClusterVector { * @param frame_number frame number of the clusters. Default is 0, which is * also used to indicate that the clusters come from many frames */ - ClusterVector(size_t cluster_size_x = 3, size_t cluster_size_y = 3, - size_t capacity = 1024, uint64_t frame_number = 0) - : m_cluster_size_x(cluster_size_x), m_cluster_size_y(cluster_size_y), - m_capacity(capacity), m_frame_number(frame_number) { + ClusterVector(size_t capacity = 1024, uint64_t frame_number = 0) + : m_capacity(capacity), m_frame_number(frame_number) { allocate_buffer(capacity); } @@ -59,10 +63,8 @@ template class ClusterVector { // Move constructor ClusterVector(ClusterVector &&other) noexcept - : m_cluster_size_x(other.m_cluster_size_x), - m_cluster_size_y(other.m_cluster_size_y), m_data(other.m_data), - m_size(other.m_size), m_capacity(other.m_capacity), - m_frame_number(other.m_frame_number) { + : m_data(other.m_data), m_size(other.m_size), + m_capacity(other.m_capacity), m_frame_number(other.m_frame_number) { other.m_data = nullptr; other.m_size = 0; other.m_capacity = 0; @@ -72,8 +74,6 @@ template class ClusterVector { ClusterVector &operator=(ClusterVector &&other) noexcept { if (this != &other) { delete[] m_data; - m_cluster_size_x = other.m_cluster_size_x; - m_cluster_size_y = other.m_cluster_size_y; m_data = other.m_data; m_size = other.m_size; m_capacity = other.m_capacity; @@ -116,8 +116,7 @@ template class ClusterVector { *reinterpret_cast(ptr) = y; ptr += sizeof(CoordType); - std::copy(data, data + m_cluster_size_x * m_cluster_size_y * sizeof(T), - ptr); + std::copy(data, data + ClusterSizeX * ClusterSizeY * sizeof(T), ptr); m_size++; } ClusterVector &operator+=(const ClusterVector &other) { @@ -137,7 +136,7 @@ template class ClusterVector { std::vector sum() { std::vector sums(m_size); const size_t stride = item_size(); - const size_t n_pixels = m_cluster_size_x * m_cluster_size_y; + const size_t n_pixels = ClusterSizeX * ClusterSizeY; std::byte *ptr = m_data + 2 * sizeof(CoordType); // skip x and y for (size_t i = 0; i < m_size; i++) { @@ -159,7 +158,7 @@ template class ClusterVector { std::vector sums(m_size); const size_t stride = item_size(); - if (m_cluster_size_x != 3 || m_cluster_size_y != 3) { + if (ClusterSizeX != 3 || ClusterSizeY != 3) { throw std::runtime_error( "Only 3x3 clusters are supported for the 2x2 sum."); } @@ -196,8 +195,7 @@ template class ClusterVector { * @brief Return the size in bytes of a single cluster */ size_t item_size() const { - return 2 * sizeof(CoordType) + - m_cluster_size_x * m_cluster_size_y * sizeof(T); + return 2 * sizeof(CoordType) + ClusterSizeX * ClusterSizeY * sizeof(T); } /** @@ -217,8 +215,8 @@ template class ClusterVector { return m_data + element_offset(i); } - size_t cluster_size_x() const { return m_cluster_size_x; } - size_t cluster_size_y() const { return m_cluster_size_y; } + // size_t cluster_size_x() const { return m_cluster_size_x; } + // size_t cluster_size_y() const { return m_cluster_size_y; } std::byte *data() { return m_data; } std::byte const *data() const { return m_data; } @@ -227,12 +225,12 @@ template class ClusterVector { * @brief Return a reference to the i-th cluster casted to type V * @tparam V type of the cluster */ - template V &at(size_t i) { - return *reinterpret_cast(element_ptr(i)); + ClusterType &at(size_t i) { + return *reinterpret_cast(element_ptr(i)); } - template const V &at(size_t i) const { - return *reinterpret_cast(element_ptr(i)); + const ClusterType &at(size_t i) const { + return *reinterpret_cast(element_ptr(i)); } const std::string_view fmt_base() const { diff --git a/src/ClusterFile.cpp b/src/ClusterFile.cpp index be3f607..c6ae470 100644 --- a/src/ClusterFile.cpp +++ b/src/ClusterFile.cpp @@ -59,8 +59,8 @@ ClusterVector ClusterFile::read_clusters(size_t n_clusters) { if (m_mode != "r") { throw std::runtime_error("File not opened for reading"); } - - ClusterVector clusters(3,3, n_clusters); + + ClusterVector clusters(3, 3, n_clusters); int32_t iframe = 0; // frame number needs to be 4 bytes! size_t nph_read = 0; @@ -78,7 +78,7 @@ ClusterVector ClusterFile::read_clusters(size_t n_clusters) { } else { nn = nph; } - nph_read += fread((buf + nph_read*clusters.item_size()), + nph_read += fread((buf + nph_read * clusters.item_size()), clusters.item_size(), nn, fp); m_num_left = nph - nn; // write back the number of photons left } @@ -93,7 +93,7 @@ ClusterVector ClusterFile::read_clusters(size_t n_clusters) { else nn = nph; - nph_read += fread((buf + nph_read*clusters.item_size()), + nph_read += fread((buf + nph_read * clusters.item_size()), clusters.item_size(), nn, fp); m_num_left = nph - nn; } @@ -112,8 +112,8 @@ ClusterVector ClusterFile::read_clusters(size_t n_clusters, ROI roi) { if (m_mode != "r") { throw std::runtime_error("File not opened for reading"); } - - ClusterVector clusters(3,3); + + ClusterVector clusters(3, 3); clusters.reserve(n_clusters); int32_t iframe = 0; // frame number needs to be 4 bytes! @@ -124,7 +124,7 @@ ClusterVector ClusterFile::read_clusters(size_t n_clusters, ROI roi) { // auto buf = reinterpret_cast(clusters.data()); // auto buf = clusters.data(); - Cluster3x3 tmp; //this would break if the cluster size changes + Cluster3x3 tmp; // this would break if the cluster size changes // if there are photons left from previous frame read them first if (nph) { @@ -135,13 +135,15 @@ ClusterVector ClusterFile::read_clusters(size_t n_clusters, ROI roi) { } else { nn = nph; } - //Read one cluster, in the ROI push back - // nph_read += fread((buf + nph_read*clusters.item_size()), - // clusters.item_size(), nn, fp); - for(size_t i = 0; i < nn; i++){ + // Read one cluster, in the ROI push back + // nph_read += fread((buf + nph_read*clusters.item_size()), + // clusters.item_size(), nn, fp); + for (size_t i = 0; i < nn; i++) { fread(&tmp, sizeof(tmp), 1, fp); - if(tmp.x >= roi.xmin && tmp.x <= roi.xmax && tmp.y >= roi.ymin && tmp.y <= roi.ymax){ - clusters.push_back(tmp.x, tmp.y, reinterpret_cast(tmp.data)); + if (tmp.x >= roi.xmin && tmp.x <= roi.xmax && tmp.y >= roi.ymin && + tmp.y <= roi.ymax) { + clusters.push_back(tmp.x, tmp.y, + reinterpret_cast(tmp.data)); nph_read++; } } @@ -161,10 +163,13 @@ ClusterVector ClusterFile::read_clusters(size_t n_clusters, ROI roi) { // nph_read += fread((buf + nph_read*clusters.item_size()), // clusters.item_size(), nn, fp); - for(size_t i = 0; i < nn; i++){ + for (size_t i = 0; i < nn; i++) { fread(&tmp, sizeof(tmp), 1, fp); - if(tmp.x >= roi.xmin && tmp.x <= roi.xmax && tmp.y >= roi.ymin && tmp.y <= roi.ymax){ - clusters.push_back(tmp.x, tmp.y, reinterpret_cast(tmp.data)); + if (tmp.x >= roi.xmin && tmp.x <= roi.xmax && + tmp.y >= roi.ymin && tmp.y <= roi.ymax) { + clusters.push_back( + tmp.x, tmp.y, + reinterpret_cast(tmp.data)); nph_read++; } } @@ -210,7 +215,6 @@ ClusterVector ClusterFile::read_frame() { return clusters; } - // std::vector ClusterFile::read_cluster_with_cut(size_t n_clusters, // double *noise_map, // int nx, int ny) { @@ -218,7 +222,8 @@ ClusterVector ClusterFile::read_frame() { // throw std::runtime_error("File not opened for reading"); // } // std::vector clusters(n_clusters); -// // size_t read_clusters_with_cut(FILE *fp, size_t n_clusters, Cluster *buf, +// // size_t read_clusters_with_cut(FILE *fp, size_t n_clusters, Cluster +// *buf, // // uint32_t *n_left, double *noise_map, int // // nx, int ny) { // int iframe = 0; @@ -249,7 +254,8 @@ ClusterVector ClusterFile::read_frame() { // for (size_t iph = 0; iph < nn; iph++) { // // read photons 1 by 1 // size_t n_read = -// fread(reinterpret_cast(ptr), sizeof(Cluster3x3), 1, fp); +// fread(reinterpret_cast(ptr), sizeof(Cluster3x3), 1, +// fp); // if (n_read != 1) { // clusters.resize(nph_read); // return clusters; @@ -257,12 +263,15 @@ ClusterVector ClusterFile::read_frame() { // // TODO! error handling on read // good = 1; // if (noise_map) { -// if (ptr->x >= 0 && ptr->x < nx && ptr->y >= 0 && ptr->y < ny) { +// if (ptr->x >= 0 && ptr->x < nx && ptr->y >= 0 && ptr->y < ny) +// { // tot1 = ptr->data[4]; -// analyze_cluster(*ptr, &t2max, &tot3, NULL, NULL, NULL, NULL, +// analyze_cluster(*ptr, &t2max, &tot3, NULL, NULL, NULL, +// NULL, // NULL); // noise = noise_map[ptr->y * nx + ptr->x]; -// if (tot1 > noise || t2max > 2 * noise || tot3 > 3 * noise) { +// if (tot1 > noise || t2max > 2 * noise || tot3 > 3 * +// noise) { // ; // } else { // good = 0; @@ -316,8 +325,8 @@ ClusterVector ClusterFile::read_frame() { // } else // good = 0; // } else { -// printf("Bad pixel number %d %d\n", ptr->x, ptr->y); -// good = 0; +// printf("Bad pixel number %d %d\n", ptr->x, +// ptr->y); good = 0; // } // } // if (good) { @@ -338,37 +347,81 @@ ClusterVector ClusterFile::read_frame() { // return clusters; // } -NDArray calculate_eta2(ClusterVector &clusters) { - //TOTO! make work with 2x2 clusters +template +NDArray calculate_eta2(ClusterVector &clusters) { + // TOTO! make work with 2x2 clusters NDArray eta2({static_cast(clusters.size()), 2}); - - if (clusters.cluster_size_x() == 3 || clusters.cluster_size_y() == 3) { - for (size_t i = 0; i < clusters.size(); i++) { - auto e = calculate_eta2(clusters.at(i)); - eta2(i, 0) = e.x; - eta2(i, 1) = e.y; - } - }else if(clusters.cluster_size_x() == 2 || clusters.cluster_size_y() == 2){ - for (size_t i = 0; i < clusters.size(); i++) { - auto e = calculate_eta2(clusters.at(i)); - eta2(i, 0) = e.x; - eta2(i, 1) = e.y; - } - }else{ - throw std::runtime_error("Only 3x3 and 2x2 clusters are supported"); + + for (size_t i = 0; i < clusters.size(); i++) { + auto e = calculate_eta2(clusters.at(i)); + eta2(i, 0) = e.x; + eta2(i, 1) = e.y; } - + return eta2; } -/** - * @brief Calculate the eta2 values for a 3x3 cluster and return them in a Eta2 struct - * containing etay, etax and the corner of the cluster. -*/ -Eta2 calculate_eta2(Cluster3x3 &cl) { +/** + * @brief Calculate the eta2 values for a generic sized cluster and return them + * in a Eta2 struct containing etay, etax and the index of the respective 2x2 + * subcluster. + */ +template +Eta2 calculate_eta2(Cluster &cl) { Eta2 eta{}; - std::array tot2; + // TODO loads of overhead for a 2x2 clsuter maybe keep 2x2 calculation + size_t num_2x2_subclusters = (ClusterSizeX - 1) * (ClusterSizeY - 1); + std::array sum_2x2_subcluster; + for (size_t i = 0; i < ClusterSizeY - 1; ++i) { + for (size_t j = 0; j < ClusterSizeX - 1; ++j) + sum_2x2_subcluster[i * (ClusterSizeX - 1) + j] = + cl.data[i * ClusterSizeX + j] + + cl.data[i * ClusterSizeX + j + 1] + + cl.data[(i + 1) * ClusterSizeX + j] + + cl.data[(i + 1) * ClusterSizeX + j + 1]; + } + + auto c = std::max_element(sum_2x2_subclusters.begin(), + sum_2x2_subcluster.end()) - + sum_2x2_subcluster.begin(); + + eta.sum = sum_2x2_subcluster[c]; + + eta.x = static_cast(cl.data[(c + 1) * ClusterSizeX + 1]) / + (cl.data[0] + cl.data[1]); + + size_t index_top_left_2x2_subcluster = + (int(c / (ClusterSizeX - 1)) + 1) * ClusterSizeX + + c % (ClusterSizeX - 1) * 2 + 1; + if ((cl.data[index_top_left_2x2_subcluster] + + cl.data[index_top_left_2x2_subcluster - 1]) != 0) + eta.x = + static_cast(cl.data[index_top_left_2x2_subcluster] / + (cl.data[index_top_left_2x2_subcluster] + + cl.data[index_top_left_2x2_subcluster - 1])); + + if ((cl.data[index_top_left_2x2_subcluster] + + cl.data[index_top_left_2x2_subcluster - ClusterSizeX]) != 0) + eta.y = static_cast( + cl.data[index_top_left_2x2_subcluster] / + (cl.data[index_top_left_2x2_subcluster] + + cl.data[index_top_left_2x2_subcluster - ClusterSizeX])); + + eta.c = c; // TODO only supported for 2x2 and 3x3 clusters -> at least no + // underyling enum class + return eta; +} + +/** + * @brief Calculate the eta2 values for a 3x3 cluster and return them in a Eta2 + * struct containing etay, etax and the corner of the cluster. + */ +template Eta2 calculate_eta2(Cluster &cl) { + Eta2 eta{}; + + std::array tot2; tot2[0] = cl.data[0] + cl.data[1] + cl.data[3] + cl.data[4]; tot2[1] = cl.data[1] + cl.data[2] + cl.data[4] + cl.data[5]; tot2[2] = cl.data[3] + cl.data[4] + cl.data[6] + cl.data[7]; @@ -379,58 +432,47 @@ Eta2 calculate_eta2(Cluster3x3 &cl) { switch (c) { case cBottomLeft: if ((cl.data[3] + cl.data[4]) != 0) - eta.x = - static_cast(cl.data[4]) / (cl.data[3] + cl.data[4]); + eta.x = static_cast(cl.data[4]) / (cl.data[3] + cl.data[4]); if ((cl.data[1] + cl.data[4]) != 0) - eta.y = - static_cast(cl.data[4]) / (cl.data[1] + cl.data[4]); + eta.y = static_cast(cl.data[4]) / (cl.data[1] + cl.data[4]); eta.c = cBottomLeft; break; case cBottomRight: if ((cl.data[2] + cl.data[5]) != 0) - eta.x = - static_cast(cl.data[5]) / (cl.data[4] + cl.data[5]); + eta.x = static_cast(cl.data[5]) / (cl.data[4] + cl.data[5]); if ((cl.data[1] + cl.data[4]) != 0) - eta.y = - static_cast(cl.data[4]) / (cl.data[1] + cl.data[4]); + eta.y = static_cast(cl.data[4]) / (cl.data[1] + cl.data[4]); eta.c = cBottomRight; break; case cTopLeft: if ((cl.data[7] + cl.data[4]) != 0) - eta.x = - static_cast(cl.data[4]) / (cl.data[3] + cl.data[4]); + eta.x = static_cast(cl.data[4]) / (cl.data[3] + cl.data[4]); if ((cl.data[7] + cl.data[4]) != 0) - eta.y = - static_cast(cl.data[7]) / (cl.data[7] + cl.data[4]); + eta.y = static_cast(cl.data[7]) / (cl.data[7] + cl.data[4]); eta.c = cTopLeft; break; case cTopRight: if ((cl.data[5] + cl.data[4]) != 0) - eta.x = - static_cast(cl.data[5]) / (cl.data[5] + cl.data[4]); + eta.x = static_cast(cl.data[5]) / (cl.data[5] + cl.data[4]); if ((cl.data[7] + cl.data[4]) != 0) - eta.y = - static_cast(cl.data[7]) / (cl.data[7] + cl.data[4]); + eta.y = static_cast(cl.data[7]) / (cl.data[7] + cl.data[4]); eta.c = cTopRight; break; - // no default to allow compiler to warn about missing cases + // no default to allow compiler to warn about missing cases } return eta; } - -Eta2 calculate_eta2(Cluster2x2 &cl) { +template Eta2 calculate_eta2(Cluster &cl) { Eta2 eta{}; eta.x = static_cast(cl.data[1]) / (cl.data[0] + cl.data[1]); eta.y = static_cast(cl.data[2]) / (cl.data[0] + cl.data[2]); - eta.sum = cl.data[0] + cl.data[1] + cl.data[2]+ cl.data[3]; - eta.c = cBottomLeft; //TODO! This is not correct, but need to put something + eta.sum = cl.data[0] + cl.data[1] + cl.data[2] + cl.data[3]; + eta.c = cBottomLeft; // TODO! This is not correct, but need to put something return eta; } - - int analyze_cluster(Cluster3x3 &cl, int32_t *t2, int32_t *t3, char *quad, double *eta2x, double *eta2y, double *eta3x, double *eta3y) { From 0876b6891ad641d534c7b39d6d5dba3256e70af5 Mon Sep 17 00:00:00 2001 From: AliceMazzoleni99 Date: Tue, 25 Mar 2025 21:42:50 +0100 Subject: [PATCH 06/51] cpp Cluster and ClusterVector and ClusterFile are templated now, they support generic cluster types --- include/aare/Cluster.hpp | 38 +++ include/aare/ClusterFile.hpp | 499 +++++++++++++++++++++++++++++++-- include/aare/ClusterVector.hpp | 13 +- include/aare/Interpolator.hpp | 26 +- src/ClusterFile.cpp | 54 ++-- src/Interpolator.cpp | 78 +++--- 6 files changed, 619 insertions(+), 89 deletions(-) create mode 100644 include/aare/Cluster.hpp diff --git a/include/aare/Cluster.hpp b/include/aare/Cluster.hpp new file mode 100644 index 0000000..74f5281 --- /dev/null +++ b/include/aare/Cluster.hpp @@ -0,0 +1,38 @@ + +/************************************************ + * @file Cluster.hpp + * @short definition of cluster, where CoordType (x,y) give + * the cluster center coordinates and data the actual cluster data + * cluster size is given as template parameters + ***********************************************/ + +#pragma once + +#include +#include + +namespace aare { + +// requires clause c++20 maybe update +template && + std::is_integral_v>> +struct Cluster { + CoordType x; + CoordType y; + T data[ClusterSizeX * ClusterSizeY]; +}; + +// Type Traits for is_cluster_type +template +struct is_cluster : std::false_type {}; // Default case: Not a Cluster + +// TODO: Do i need the require clause here as well? +template +struct is_cluster> : std::true_type {}; // Cluster + +// helper +template constexpr bool is_cluster_v = is_cluster::value; + +} // namespace aare diff --git a/include/aare/ClusterFile.hpp b/include/aare/ClusterFile.hpp index d35f362..d61ee2b 100644 --- a/include/aare/ClusterFile.hpp +++ b/include/aare/ClusterFile.hpp @@ -1,5 +1,6 @@ #pragma once +#include "aare/Cluster.hpp" #include "aare/ClusterVector.hpp" #include "aare/NDArray.hpp" #include "aare/defs.hpp" @@ -8,14 +9,6 @@ namespace aare { -template -struct Cluster { - CoordType x; - CoordType y; - T data[ClusterSizeX * ClusterSizeY]; -}; - typedef enum { cBottomLeft = 0, cBottomRight = 1, @@ -59,6 +52,8 @@ uint32_t number_of_clusters .... */ +// TODO: change to support any type of clusters, e.g. header line with +// clsuter_size_x, cluster_size_y, /** * @brief Class to read and write cluster files * Expects data to be laid out as: @@ -71,6 +66,8 @@ uint32_t number_of_clusters * uint32_t number_of_clusters * etc. */ +template , bool>> class ClusterFile { FILE *fp{}; uint32_t m_num_left{}; @@ -97,9 +94,9 @@ class ClusterFile { * If EOF is reached the returned vector will have less than n_clusters * clusters */ - ClusterVector read_clusters(size_t n_clusters); + ClusterVector read_clusters(size_t n_clusters); - ClusterVector read_clusters(size_t n_clusters, ROI roi); + ClusterVector read_clusters(size_t n_clusters, ROI roi); /** * @brief Read a single frame from the file and return the clusters. The @@ -107,9 +104,9 @@ class ClusterFile { * @throws std::runtime_error if the file is not opened for reading or the * file pointer not at the beginning of a frame */ - ClusterVector read_frame(); + ClusterVector read_frame(); - void write_frame(const ClusterVector &clusters); + void write_frame(const ClusterVector &clusters); // Need to be migrated to support NDArray and return a ClusterVector // std::vector @@ -130,20 +127,484 @@ class ClusterFile { int analyze_data(int32_t *data, int32_t *t2, int32_t *t3, char *quad, double *eta2x, double *eta2y, double *eta3x, double *eta3y); -int analyze_cluster(Cluster3x3 &cl, int32_t *t2, int32_t *t3, char *quad, - double *eta2x, double *eta2y, double *eta3x, double *eta3y); +int analyze_cluster(Cluster &cl, int32_t *t2, int32_t *t3, + char *quad, double *eta2x, double *eta2y, double *eta3x, + double *eta3y); -template +template >> NDArray calculate_eta2(ClusterVector &clusters); -template Eta2 calculate_eta2(Cluster &cl); +// TODO: do we need rquire clauses? +template Eta2 calculate_eta2(const Cluster &cl); -Eta2 calculate_eta2(Cluster2x2 &cl); +template Eta2 calculate_eta2(const Cluster &cl); -template Eta2 calculate_eta2(ClusterType &cl); +template >> +Eta2 calculate_eta2(const ClusterType &cl); template -Eta2 calculate_eta2(Cluster &cl); +Eta2 calculate_eta2( + const Cluster &cl); + +template +ClusterFile::ClusterFile( + const std::filesystem::path &fname, size_t chunk_size, + const std::string &mode) + : m_chunk_size(chunk_size), m_mode(mode) { + + if (mode == "r") { + fp = fopen(fname.c_str(), "rb"); + if (!fp) { + throw std::runtime_error("Could not open file for reading: " + + fname.string()); + } + } else if (mode == "w") { + fp = fopen(fname.c_str(), "wb"); + if (!fp) { + throw std::runtime_error("Could not open file for writing: " + + fname.string()); + } + } else if (mode == "a") { + fp = fopen(fname.c_str(), "ab"); + if (!fp) { + throw std::runtime_error("Could not open file for appending: " + + fname.string()); + } + } else { + throw std::runtime_error("Unsupported mode: " + mode); + } +} + +template +ClusterFile::~ClusterFile() { + close(); +} + +template +void ClusterFile::close() { + if (fp) { + fclose(fp); + fp = nullptr; + } +} + +// TODO generally supported for all clsuter types +template +void ClusterFile::write_frame( + const ClusterVector &clusters) { + if (m_mode != "w" && m_mode != "a") { + throw std::runtime_error("File not opened for writing"); + } + if (!(clusters.cluster_size_x() == 3) && + !(clusters.cluster_size_y() == 3)) { + throw std::runtime_error("Only 3x3 clusters are supported"); + } + int32_t frame_number = clusters.frame_number(); + fwrite(&frame_number, sizeof(frame_number), 1, fp); + uint32_t n_clusters = clusters.size(); + fwrite(&n_clusters, sizeof(n_clusters), 1, fp); + fwrite(clusters.data(), clusters.item_size(), clusters.size(), fp); +} + +template +ClusterVector +ClusterFile::read_clusters(size_t n_clusters) { + if (m_mode != "r") { + throw std::runtime_error("File not opened for reading"); + } + + ClusterVector clusters(n_clusters); + + int32_t iframe = 0; // frame number needs to be 4 bytes! + size_t nph_read = 0; + uint32_t nn = m_num_left; + uint32_t nph = m_num_left; // number of clusters in frame needs to be 4 + + // auto buf = reinterpret_cast(clusters.data()); + auto buf = clusters.data(); + // if there are photons left from previous frame read them first + if (nph) { + if (nph > n_clusters) { + // if we have more photons left in the frame then photons to read we + // read directly the requested number + nn = n_clusters; + } else { + nn = nph; + } + nph_read += fread((buf + nph_read * clusters.item_size()), + clusters.item_size(), nn, fp); + m_num_left = nph - nn; // write back the number of photons left + } + + if (nph_read < n_clusters) { + // keep on reading frames and photons until reaching n_clusters + while (fread(&iframe, sizeof(iframe), 1, fp)) { + // read number of clusters in frame + if (fread(&nph, sizeof(nph), 1, fp)) { + if (nph > (n_clusters - nph_read)) + nn = n_clusters - nph_read; + else + nn = nph; + + nph_read += fread((buf + nph_read * clusters.item_size()), + clusters.item_size(), nn, fp); + m_num_left = nph - nn; + } + if (nph_read >= n_clusters) + break; + } + } + + // Resize the vector to the number of clusters. + // No new allocation, only change bounds. + clusters.resize(nph_read); + return clusters; +} + +template +ClusterVector +ClusterFile::read_clusters(size_t n_clusters, ROI roi) { + if (m_mode != "r") { + throw std::runtime_error("File not opened for reading"); + } + + ClusterVector clusters; + clusters.reserve(n_clusters); + + int32_t iframe = 0; // frame number needs to be 4 bytes! + size_t nph_read = 0; + uint32_t nn = m_num_left; + uint32_t nph = m_num_left; // number of clusters in frame needs to be 4 + + // auto buf = reinterpret_cast(clusters.data()); + // auto buf = clusters.data(); + + ClusterType tmp; // this would break if the cluster size changes + + // if there are photons left from previous frame read them first + if (nph) { + if (nph > n_clusters) { + // if we have more photons left in the frame then photons to read we + // read directly the requested number + nn = n_clusters; + } else { + nn = nph; + } + // Read one cluster, in the ROI push back + // nph_read += fread((buf + nph_read*clusters.item_size()), + // clusters.item_size(), nn, fp); + for (size_t i = 0; i < nn; i++) { + fread(&tmp, sizeof(tmp), 1, fp); + if (tmp.x >= roi.xmin && tmp.x <= roi.xmax && tmp.y >= roi.ymin && + tmp.y <= roi.ymax) { + clusters.push_back(tmp.x, tmp.y, + reinterpret_cast(tmp.data)); + nph_read++; + } + } + + m_num_left = nph - nn; // write back the number of photons left + } + + if (nph_read < n_clusters) { + // keep on reading frames and photons until reaching n_clusters + while (fread(&iframe, sizeof(iframe), 1, fp)) { + // read number of clusters in frame + if (fread(&nph, sizeof(nph), 1, fp)) { + if (nph > (n_clusters - nph_read)) + nn = n_clusters - nph_read; + else + nn = nph; + + // nph_read += fread((buf + nph_read*clusters.item_size()), + // clusters.item_size(), nn, fp); + for (size_t i = 0; i < nn; i++) { + fread(&tmp, sizeof(tmp), 1, fp); + if (tmp.x >= roi.xmin && tmp.x <= roi.xmax && + tmp.y >= roi.ymin && tmp.y <= roi.ymax) { + clusters.push_back( + tmp.x, tmp.y, + reinterpret_cast(tmp.data)); + nph_read++; + } + } + m_num_left = nph - nn; + } + if (nph_read >= n_clusters) + break; + } + } + + // Resize the vector to the number of clusters. + // No new allocation, only change bounds. + clusters.resize(nph_read); + return clusters; +} + +template +ClusterVector ClusterFile::read_frame() { + if (m_mode != "r") { + throw std::runtime_error("File not opened for reading"); + } + if (m_num_left) { + throw std::runtime_error( + "There are still photons left in the last frame"); + } + int32_t frame_number; + if (fread(&frame_number, sizeof(frame_number), 1, fp) != 1) { + throw std::runtime_error("Could not read frame number"); + } + + int32_t n_clusters; // Saved as 32bit integer in the cluster file + if (fread(&n_clusters, sizeof(n_clusters), 1, fp) != 1) { + throw std::runtime_error("Could not read number of clusters"); + } + // std::vector clusters(n_clusters); + ClusterVector clusters(n_clusters); + clusters.set_frame_number(frame_number); + + if (fread(clusters.data(), clusters.item_size(), n_clusters, fp) != + static_cast(n_clusters)) { + throw std::runtime_error("Could not read clusters"); + } + clusters.resize(n_clusters); + return clusters; +} + +template >> +NDArray calculate_eta2(const ClusterVector &clusters) { + // TOTO! make work with 2x2 clusters + NDArray eta2({static_cast(clusters.size()), 2}); + + for (size_t i = 0; i < clusters.size(); i++) { + auto e = calculate_eta2(clusters.at(i)); + eta2(i, 0) = e.x; + eta2(i, 1) = e.y; + } + + return eta2; +} + +/** + * @brief Calculate the eta2 values for a generic sized cluster and return them + * in a Eta2 struct containing etay, etax and the index of the respective 2x2 + * subcluster. + */ +template +Eta2 calculate_eta2( + const Cluster &cl) { + Eta2 eta{}; + + // TODO loads of overhead for a 2x2 clsuter maybe keep 2x2 calculation + constexpr size_t num_2x2_subclusters = + (ClusterSizeX - 1) * (ClusterSizeY - 1); + std::array sum_2x2_subcluster; + for (size_t i = 0; i < ClusterSizeY - 1; ++i) { + for (size_t j = 0; j < ClusterSizeX - 1; ++j) + sum_2x2_subcluster[i * (ClusterSizeX - 1) + j] = + cl.data[i * ClusterSizeX + j] + + cl.data[i * ClusterSizeX + j + 1] + + cl.data[(i + 1) * ClusterSizeX + j] + + cl.data[(i + 1) * ClusterSizeX + j + 1]; + } + + auto c = + std::max_element(sum_2x2_subcluster.begin(), sum_2x2_subcluster.end()) - + sum_2x2_subcluster.begin(); + + eta.sum = sum_2x2_subcluster[c]; + + eta.x = static_cast(cl.data[(c + 1) * ClusterSizeX + 1]) / + (cl.data[0] + cl.data[1]); + + size_t index_top_left_2x2_subcluster = + (int(c / (ClusterSizeX - 1)) + 1) * ClusterSizeX + + c % (ClusterSizeX - 1) * 2 + 1; + if ((cl.data[index_top_left_2x2_subcluster] + + cl.data[index_top_left_2x2_subcluster - 1]) != 0) + eta.x = + static_cast(cl.data[index_top_left_2x2_subcluster] / + (cl.data[index_top_left_2x2_subcluster] + + cl.data[index_top_left_2x2_subcluster - 1])); + + if ((cl.data[index_top_left_2x2_subcluster] + + cl.data[index_top_left_2x2_subcluster - ClusterSizeX]) != 0) + eta.y = static_cast( + cl.data[index_top_left_2x2_subcluster] / + (cl.data[index_top_left_2x2_subcluster] + + cl.data[index_top_left_2x2_subcluster - ClusterSizeX])); + + eta.c = c; // TODO only supported for 2x2 and 3x3 clusters -> at least no + // underyling enum class + return eta; +} + +/** + * @brief Calculate the eta2 values for a 3x3 cluster and return them in a Eta2 + * struct containing etay, etax and the corner of the cluster. + */ +template Eta2 calculate_eta2(const Cluster &cl) { + Eta2 eta{}; + + std::array tot2; + tot2[0] = cl.data[0] + cl.data[1] + cl.data[3] + cl.data[4]; + tot2[1] = cl.data[1] + cl.data[2] + cl.data[4] + cl.data[5]; + tot2[2] = cl.data[3] + cl.data[4] + cl.data[6] + cl.data[7]; + tot2[3] = cl.data[4] + cl.data[5] + cl.data[7] + cl.data[8]; + + auto c = std::max_element(tot2.begin(), tot2.end()) - tot2.begin(); + eta.sum = tot2[c]; + switch (c) { + case cBottomLeft: + if ((cl.data[3] + cl.data[4]) != 0) + eta.x = static_cast(cl.data[4]) / (cl.data[3] + cl.data[4]); + if ((cl.data[1] + cl.data[4]) != 0) + eta.y = static_cast(cl.data[4]) / (cl.data[1] + cl.data[4]); + eta.c = cBottomLeft; + break; + case cBottomRight: + if ((cl.data[2] + cl.data[5]) != 0) + eta.x = static_cast(cl.data[5]) / (cl.data[4] + cl.data[5]); + if ((cl.data[1] + cl.data[4]) != 0) + eta.y = static_cast(cl.data[4]) / (cl.data[1] + cl.data[4]); + eta.c = cBottomRight; + break; + case cTopLeft: + if ((cl.data[7] + cl.data[4]) != 0) + eta.x = static_cast(cl.data[4]) / (cl.data[3] + cl.data[4]); + if ((cl.data[7] + cl.data[4]) != 0) + eta.y = static_cast(cl.data[7]) / (cl.data[7] + cl.data[4]); + eta.c = cTopLeft; + break; + case cTopRight: + if ((cl.data[5] + cl.data[4]) != 0) + eta.x = static_cast(cl.data[5]) / (cl.data[5] + cl.data[4]); + if ((cl.data[7] + cl.data[4]) != 0) + eta.y = static_cast(cl.data[7]) / (cl.data[7] + cl.data[4]); + eta.c = cTopRight; + break; + } + return eta; +} + +template Eta2 calculate_eta2(const Cluster &cl) { + Eta2 eta{}; + + eta.x = static_cast(cl.data[1]) / (cl.data[0] + cl.data[1]); + eta.y = static_cast(cl.data[2]) / (cl.data[0] + cl.data[2]); + eta.sum = cl.data[0] + cl.data[1] + cl.data[2] + cl.data[3]; + eta.c = cBottomLeft; // TODO! This is not correct, but need to put something + return eta; +} + +// TODO complicated API simplify? +int analyze_cluster(Cluster &cl, int32_t *t2, int32_t *t3, + char *quad, double *eta2x, double *eta2y, double *eta3x, + double *eta3y) { + + return analyze_data(cl.data, t2, t3, quad, eta2x, eta2y, eta3x, eta3y); +} + +int analyze_data(int32_t *data, int32_t *t2, int32_t *t3, char *quad, + double *eta2x, double *eta2y, double *eta3x, double *eta3y) { + + int ok = 1; + + int32_t tot2[4]; + int32_t t2max = 0; + char c = 0; + int32_t val, tot3; + + tot3 = 0; + for (int i = 0; i < 4; i++) + tot2[i] = 0; + + for (int ix = 0; ix < 3; ix++) { + for (int iy = 0; iy < 3; iy++) { + val = data[iy * 3 + ix]; + // printf ("%d ",data[iy * 3 + ix]); + tot3 += val; + if (ix <= 1 && iy <= 1) + tot2[cBottomLeft] += val; + if (ix >= 1 && iy <= 1) + tot2[cBottomRight] += val; + if (ix <= 1 && iy >= 1) + tot2[cTopLeft] += val; + if (ix >= 1 && iy >= 1) + tot2[cTopRight] += val; + } + // printf ("\n"); + } + // printf ("\n"); + + if (t2 || quad) { + + t2max = tot2[0]; + c = cBottomLeft; + for (int i = 1; i < 4; i++) { + if (tot2[i] > t2max) { + t2max = tot2[i]; + c = i; + } + } + // printf("*** %d %d %d %d -- + // %d\n",tot2[0],tot2[1],tot2[2],tot2[3],t2max); + if (quad) + *quad = c; + if (t2) + *t2 = t2max; + } + + if (t3) + *t3 = tot3; + + if (eta2x || eta2y) { + if (eta2x) + *eta2x = 0; + if (eta2y) + *eta2y = 0; + switch (c) { + case cBottomLeft: + if (eta2x && (data[3] + data[4]) != 0) + *eta2x = static_cast(data[4]) / (data[3] + data[4]); + if (eta2y && (data[1] + data[4]) != 0) + *eta2y = static_cast(data[4]) / (data[1] + data[4]); + break; + case cBottomRight: + if (eta2x && (data[2] + data[5]) != 0) + *eta2x = static_cast(data[5]) / (data[4] + data[5]); + if (eta2y && (data[1] + data[4]) != 0) + *eta2y = static_cast(data[4]) / (data[1] + data[4]); + break; + case cTopLeft: + if (eta2x && (data[7] + data[4]) != 0) + *eta2x = static_cast(data[4]) / (data[3] + data[4]); + if (eta2y && (data[7] + data[4]) != 0) + *eta2y = static_cast(data[7]) / (data[7] + data[4]); + break; + case cTopRight: + if (eta2x && t2max != 0) + *eta2x = static_cast(data[5]) / (data[5] + data[4]); + if (eta2y && t2max != 0) + *eta2y = static_cast(data[7]) / (data[7] + data[4]); + break; + default:; + } + } + + if (eta3x || eta3y) { + if (eta3x && (data[3] + data[4] + data[5]) != 0) + *eta3x = static_cast(-data[3] + data[3 + 2]) / + (data[3] + data[4] + data[5]); + if (eta3y && (data[1] + data[4] + data[7]) != 0) + *eta3y = static_cast(-data[1] + data[2 * 3 + 1]) / + (data[1] + data[4] + data[7]); + } + + return ok; +} } // namespace aare diff --git a/include/aare/ClusterVector.hpp b/include/aare/ClusterVector.hpp index c5e66b7..ec0fa40 100644 --- a/include/aare/ClusterVector.hpp +++ b/include/aare/ClusterVector.hpp @@ -1,4 +1,5 @@ #pragma once +#include "aare/Cluster.hpp" //TODO maybe store in seperate file !!! #include #include #include @@ -10,7 +11,9 @@ namespace aare { -template class ClusterVector; // Forward declaration +template >> +class ClusterVector; // Forward declaration /** * @brief ClusterVector is a container for clusters of various sizes. It uses a @@ -44,12 +47,10 @@ class ClusterVector> { constexpr static char m_fmt_base[] = "=h:x:\nh:y:\n({},{}){}:data:"; public: - using ClusterType = Cluster; + using ClusterType = Cluster; /** * @brief Construct a new ClusterVector object - * @param cluster_size_x size of the cluster in x direction - * @param cluster_size_y size of the cluster in y direction * @param capacity initial capacity of the buffer in number of clusters * @param frame_number frame number of the clusters. Default is 0, which is * also used to indicate that the clusters come from many frames @@ -184,6 +185,10 @@ class ClusterVector> { */ size_t size() const { return m_size; } + uint8_t cluster_size_x() const { return ClusterSizeX; } + + uint8_t cluster_size_y() const { return ClusterSizeY; } + /** * @brief Return the capacity of the buffer in number of clusters. This is * the number of clusters that can be stored in the current buffer without diff --git a/include/aare/Interpolator.hpp b/include/aare/Interpolator.hpp index 4905bce..5843046 100644 --- a/include/aare/Interpolator.hpp +++ b/include/aare/Interpolator.hpp @@ -1,29 +1,35 @@ #pragma once + +#include "aare/Cluster.hpp" +#include "aare/ClusterFile.hpp" //Cluster_3x3 +#include "aare/ClusterVector.hpp" #include "aare/NDArray.hpp" #include "aare/NDView.hpp" -#include "aare/ClusterVector.hpp" -#include "aare/ClusterFile.hpp" //Cluster_3x3 -namespace aare{ +namespace aare { -struct Photon{ +struct Photon { double x; double y; double energy; }; -class Interpolator{ +class Interpolator { NDArray m_ietax; NDArray m_ietay; NDArray m_etabinsx; NDArray m_etabinsy; NDArray m_energy_bins; - public: - Interpolator(NDView etacube, NDView xbins, NDView ybins, NDView ebins); - NDArray get_ietax(){return m_ietax;} - NDArray get_ietay(){return m_ietay;} - std::vector interpolate(const ClusterVector& clusters); + public: + Interpolator(NDView etacube, NDView xbins, + NDView ybins, NDView ebins); + NDArray get_ietax() { return m_ietax; } + NDArray get_ietay() { return m_ietay; } + + template >> + std::vector interpolate(const ClusterVector &clusters); }; } // namespace aare \ No newline at end of file diff --git a/src/ClusterFile.cpp b/src/ClusterFile.cpp index c6ae470..0fc5764 100644 --- a/src/ClusterFile.cpp +++ b/src/ClusterFile.cpp @@ -4,8 +4,11 @@ namespace aare { -ClusterFile::ClusterFile(const std::filesystem::path &fname, size_t chunk_size, - const std::string &mode) +template >> +ClusterFile::ClusterFile(const std::filesystem::path &fname, + size_t chunk_size, + const std::string &mode) : m_chunk_size(chunk_size), m_mode(mode) { if (mode == "r") { @@ -31,16 +34,21 @@ ClusterFile::ClusterFile(const std::filesystem::path &fname, size_t chunk_size, } } -ClusterFile::~ClusterFile() { close(); } +template ClusterFile::~ClusterFile() { + close(); +} -void ClusterFile::close() { +template void ClusterFile::close() { if (fp) { fclose(fp); fp = nullptr; } } -void ClusterFile::write_frame(const ClusterVector &clusters) { +// TODO generally supported for all clsuter types +template +void ClusterFile::write_frame( + const ClusterVector &clusters) { if (m_mode != "w" && m_mode != "a") { throw std::runtime_error("File not opened for writing"); } @@ -55,12 +63,14 @@ void ClusterFile::write_frame(const ClusterVector &clusters) { fwrite(clusters.data(), clusters.item_size(), clusters.size(), fp); } -ClusterVector ClusterFile::read_clusters(size_t n_clusters) { +template +ClusterVector +ClusterFile::read_clusters(size_t n_clusters) { if (m_mode != "r") { throw std::runtime_error("File not opened for reading"); } - ClusterVector clusters(3, 3, n_clusters); + ClusterVector clusters(n_clusters); int32_t iframe = 0; // frame number needs to be 4 bytes! size_t nph_read = 0; @@ -108,12 +118,14 @@ ClusterVector ClusterFile::read_clusters(size_t n_clusters) { return clusters; } -ClusterVector ClusterFile::read_clusters(size_t n_clusters, ROI roi) { +template +ClusterVector +ClusterFile::read_clusters(size_t n_clusters, ROI roi) { if (m_mode != "r") { throw std::runtime_error("File not opened for reading"); } - ClusterVector clusters(3, 3); + ClusterVector clusters; clusters.reserve(n_clusters); int32_t iframe = 0; // frame number needs to be 4 bytes! @@ -124,7 +136,7 @@ ClusterVector ClusterFile::read_clusters(size_t n_clusters, ROI roi) { // auto buf = reinterpret_cast(clusters.data()); // auto buf = clusters.data(); - Cluster3x3 tmp; // this would break if the cluster size changes + ClusterType tmp; // this would break if the cluster size changes // if there are photons left from previous frame read them first if (nph) { @@ -186,7 +198,8 @@ ClusterVector ClusterFile::read_clusters(size_t n_clusters, ROI roi) { return clusters; } -ClusterVector ClusterFile::read_frame() { +template +ClusterVector ClusterFile::read_frame() { if (m_mode != "r") { throw std::runtime_error("File not opened for reading"); } @@ -204,7 +217,7 @@ ClusterVector ClusterFile::read_frame() { throw std::runtime_error("Could not read number of clusters"); } // std::vector clusters(n_clusters); - ClusterVector clusters(3, 3, n_clusters); + ClusterVector clusters(n_clusters); clusters.set_frame_number(frame_number); if (fread(clusters.data(), clusters.item_size(), n_clusters, fp) != @@ -372,8 +385,9 @@ Eta2 calculate_eta2(Cluster &cl) { Eta2 eta{}; // TODO loads of overhead for a 2x2 clsuter maybe keep 2x2 calculation - size_t num_2x2_subclusters = (ClusterSizeX - 1) * (ClusterSizeY - 1); - std::array sum_2x2_subcluster; + constexpr size_t num_2x2_subclusters = + (ClusterSizeX - 1) * (ClusterSizeY - 1); + std::array sum_2x2_subcluster; for (size_t i = 0; i < ClusterSizeY - 1; ++i) { for (size_t j = 0; j < ClusterSizeX - 1; ++j) sum_2x2_subcluster[i * (ClusterSizeX - 1) + j] = @@ -383,9 +397,9 @@ Eta2 calculate_eta2(Cluster &cl) { cl.data[(i + 1) * ClusterSizeX + j + 1]; } - auto c = std::max_element(sum_2x2_subclusters.begin(), - sum_2x2_subcluster.end()) - - sum_2x2_subcluster.begin(); + auto c = + std::max_element(sum_2x2_subcluster.begin(), sum_2x2_subcluster.end()) - + sum_2x2_subcluster.begin(); eta.sum = sum_2x2_subcluster[c]; @@ -458,7 +472,6 @@ template Eta2 calculate_eta2(Cluster &cl) { eta.y = static_cast(cl.data[7]) / (cl.data[7] + cl.data[4]); eta.c = cTopRight; break; - // no default to allow compiler to warn about missing cases } return eta; } @@ -473,8 +486,9 @@ template Eta2 calculate_eta2(Cluster &cl) { return eta; } -int analyze_cluster(Cluster3x3 &cl, int32_t *t2, int32_t *t3, char *quad, - double *eta2x, double *eta2y, double *eta3x, +// TODO complicated API simplify? +int analyze_cluster(Cluster &cl, int32_t *t2, int32_t *t3, + char *quad, double *eta2x, double *eta2y, double *eta3x, double *eta3y) { return analyze_data(cl.data, t2, t3, quad, eta2x, eta2y, eta3x, eta3y); diff --git a/src/Interpolator.cpp b/src/Interpolator.cpp index 85e0b5d..d95405a 100644 --- a/src/Interpolator.cpp +++ b/src/Interpolator.cpp @@ -5,7 +5,8 @@ namespace aare { Interpolator::Interpolator(NDView etacube, NDView xbins, NDView ybins, NDView ebins) - : m_ietax(etacube), m_ietay(etacube), m_etabinsx(xbins), m_etabinsy(ybins), m_energy_bins(ebins) { + : m_ietax(etacube), m_ietay(etacube), m_etabinsx(xbins), m_etabinsy(ybins), + m_energy_bins(ebins) { if (etacube.shape(0) != xbins.size() || etacube.shape(1) != ybins.size() || etacube.shape(2) != ebins.size()) { throw std::invalid_argument( @@ -51,35 +52,37 @@ Interpolator::Interpolator(NDView etacube, NDView xbins, } } } - } -std::vector Interpolator::interpolate(const ClusterVector& clusters) { +template >> +std::vector +Interpolator::interpolate(const ClusterVector &clusters) { std::vector photons; photons.reserve(clusters.size()); if (clusters.cluster_size_x() == 3 || clusters.cluster_size_y() == 3) { - for (size_t i = 0; i(i); - Eta2 eta= calculate_eta2(cluster); - Photon photon; photon.x = cluster.x; photon.y = cluster.y; photon.energy = eta.sum; - + // auto ie = nearest_index(m_energy_bins, photon.energy)-1; // auto ix = nearest_index(m_etabinsx, eta.x)-1; - // auto iy = nearest_index(m_etabinsy, eta.y)-1; - //Finding the index of the last element that is smaller - //should work fine as long as we have many bins + // auto iy = nearest_index(m_etabinsy, eta.y)-1; + // Finding the index of the last element that is smaller + // should work fine as long as we have many bins auto ie = last_smaller(m_energy_bins, photon.energy); auto ix = last_smaller(m_etabinsx, eta.x); - auto iy = last_smaller(m_etabinsy, eta.y); + auto iy = last_smaller(m_etabinsy, eta.y); // fmt::print("ex: {}, ix: {}, iy: {}\n", ie, ix, iy); - + double dX, dY; int ex, ey; // cBottomLeft = 0, @@ -100,44 +103,47 @@ std::vector Interpolator::interpolate(const ClusterVector& clus dY = -1.; break; case cBottomRight: - dX = 0.; + dX = 0.; dY = -1.; break; } - photon.x += m_ietax(ix, iy, 0)*2 + dX; - photon.y += m_ietay(ix, iy, 0)*2 + dY; + photon.x += m_ietax(ix, iy, 0) * 2 + dX; + photon.y += m_ietay(ix, iy, 0) * 2 + dY; photons.push_back(photon); } - }else if(clusters.cluster_size_x() == 2 || clusters.cluster_size_y() == 2){ - for (size_t i = 0; i(i); - Eta2 eta= calculate_eta2(cluster); - + } else if (clusters.cluster_size_x() == 2 || + clusters.cluster_size_y() == 2) { + for (size_t i = 0; i < clusters.size(); i++) { + auto cluster = clusters.at(i); + Eta2 eta = calculate_eta2(cluster); + Photon photon; photon.x = cluster.x; photon.y = cluster.y; photon.energy = eta.sum; - - //Now do some actual interpolation. - //Find which energy bin the cluster is in - // auto ie = nearest_index(m_energy_bins, photon.energy)-1; - // auto ix = nearest_index(m_etabinsx, eta.x)-1; - // auto iy = nearest_index(m_etabinsy, eta.y)-1; - //Finding the index of the last element that is smaller - //should work fine as long as we have many bins + + // Now do some actual interpolation. + // Find which energy bin the cluster is in + // auto ie = nearest_index(m_energy_bins, photon.energy)-1; + // auto ix = nearest_index(m_etabinsx, eta.x)-1; + // auto iy = nearest_index(m_etabinsy, eta.y)-1; + // Finding the index of the last element that is smaller + // should work fine as long as we have many bins auto ie = last_smaller(m_energy_bins, photon.energy); auto ix = last_smaller(m_etabinsx, eta.x); - auto iy = last_smaller(m_etabinsy, eta.y); + auto iy = last_smaller(m_etabinsy, eta.y); - photon.x += m_ietax(ix, iy, 0)*2; //eta goes between 0 and 1 but we could move the hit anywhere in the 2x2 - photon.y += m_ietay(ix, iy, 0)*2; + photon.x += + m_ietax(ix, iy, 0) * 2; // eta goes between 0 and 1 but we could + // move the hit anywhere in the 2x2 + photon.y += m_ietay(ix, iy, 0) * 2; photons.push_back(photon); } - - }else{ - throw std::runtime_error("Only 3x3 and 2x2 clusters are supported for interpolation"); + + } else { + throw std::runtime_error( + "Only 3x3 and 2x2 clusters are supported for interpolation"); } - return photons; } From f8f98b6ec3438902d4c6b23008e01fefe331bc76 Mon Sep 17 00:00:00 2001 From: AliceMazzoleni99 Date: Fri, 28 Mar 2025 14:29:20 +0100 Subject: [PATCH 07/51] Generalized calculate_eta2 function to work with general cluster types --- CMakeLists.txt | 14 ++++---- include/aare/ClusterFile.hpp | 63 +++++++++++++++++----------------- src/Cluster.test.cpp | 65 ++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 36 deletions(-) create mode 100644 src/Cluster.test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4772f0b..568d868 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,7 +31,7 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) # General options -option(AARE_PYTHON_BINDINGS "Build python bindings" ON) +option(AARE_PYTHON_BINDINGS "Build python bindings" OFF) option(AARE_TESTS "Build tests" OFF) option(AARE_BENCHMARKS "Build benchmarks" OFF) option(AARE_EXAMPLES "Build examples" OFF) @@ -307,7 +307,8 @@ endif() set(PUBLICHEADERS include/aare/ArrayExpr.hpp - include/aare/ClusterFinder.hpp + include/aare/Cluster.hpp + #include/aare/ClusterFinder.hpp include/aare/ClusterFile.hpp include/aare/CtbRawFile.hpp include/aare/ClusterVector.hpp @@ -328,7 +329,7 @@ set(PUBLICHEADERS include/aare/RawFile.hpp include/aare/RawMasterFile.hpp include/aare/RawSubFile.hpp - include/aare/VarClusterFinder.hpp + #include/aare/VarClusterFinder.hpp include/aare/utils/task.hpp ) @@ -336,7 +337,7 @@ set(PUBLICHEADERS set(SourceFiles ${CMAKE_CURRENT_SOURCE_DIR}/src/CtbRawFile.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/ClusterFile.cpp + #${CMAKE_CURRENT_SOURCE_DIR}/src/ClusterFile.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/defs.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Dtype.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/decode.cpp @@ -394,8 +395,9 @@ if(AARE_TESTS) ${CMAKE_CURRENT_SOURCE_DIR}/src/RawMasterFile.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/NDArray.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/NDView.test.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/ClusterFinder.test.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/ClusterVector.test.cpp + #${CMAKE_CURRENT_SOURCE_DIR}/src/ClusterFinder.test.cpp + #${CMAKE_CURRENT_SOURCE_DIR}/src/ClusterVector.test.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Cluster.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Pedestal.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/NumpyFile.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/NumpyHelpers.test.cpp diff --git a/include/aare/ClusterFile.hpp b/include/aare/ClusterFile.hpp index d61ee2b..3a7dab8 100644 --- a/include/aare/ClusterFile.hpp +++ b/include/aare/ClusterFile.hpp @@ -28,10 +28,11 @@ typedef enum { pTopRight = 8 } pixel; +// TODO: maybe template this!!!!!! why int32_t???? struct Eta2 { double x; double y; - corner c; + int c; int32_t sum; }; @@ -131,22 +132,22 @@ int analyze_cluster(Cluster &cl, int32_t *t2, int32_t *t3, char *quad, double *eta2x, double *eta2y, double *eta3x, double *eta3y); -template >> -NDArray calculate_eta2(ClusterVector &clusters); +// template >> +// NDArray calculate_eta2(ClusterVector &clusters); // TODO: do we need rquire clauses? -template Eta2 calculate_eta2(const Cluster &cl); +// template Eta2 calculate_eta2(const Cluster &cl); -template Eta2 calculate_eta2(const Cluster &cl); +// template Eta2 calculate_eta2(const Cluster &cl); -template >> -Eta2 calculate_eta2(const ClusterType &cl); +// template >> +// Eta2 calculate_eta2(const ClusterType &cl); -template -Eta2 calculate_eta2( - const Cluster &cl); +// template +// Eta2 calculate_eta2( +// const Cluster &cl); template ClusterFile::ClusterFile( @@ -379,7 +380,7 @@ NDArray calculate_eta2(const ClusterVector &clusters) { NDArray eta2({static_cast(clusters.size()), 2}); for (size_t i = 0; i < clusters.size(); i++) { - auto e = calculate_eta2(clusters.at(i)); + auto e = calculate_eta2(clusters.at(i)); eta2(i, 0) = e.x; eta2(i, 1) = e.y; } @@ -417,25 +418,23 @@ Eta2 calculate_eta2( eta.sum = sum_2x2_subcluster[c]; - eta.x = static_cast(cl.data[(c + 1) * ClusterSizeX + 1]) / - (cl.data[0] + cl.data[1]); + size_t index_bottom_left_max_2x2_subcluster = + (int(c / (ClusterSizeX - 1))) * ClusterSizeX + c % (ClusterSizeX - 1); - size_t index_top_left_2x2_subcluster = - (int(c / (ClusterSizeX - 1)) + 1) * ClusterSizeX + - c % (ClusterSizeX - 1) * 2 + 1; - if ((cl.data[index_top_left_2x2_subcluster] + - cl.data[index_top_left_2x2_subcluster - 1]) != 0) - eta.x = - static_cast(cl.data[index_top_left_2x2_subcluster] / - (cl.data[index_top_left_2x2_subcluster] + - cl.data[index_top_left_2x2_subcluster - 1])); + if ((cl.data[index_bottom_left_max_2x2_subcluster] + + cl.data[index_bottom_left_max_2x2_subcluster + 1]) != 0) + eta.x = static_cast( + cl.data[index_bottom_left_max_2x2_subcluster + 1]) / + (cl.data[index_bottom_left_max_2x2_subcluster] + + cl.data[index_bottom_left_max_2x2_subcluster + 1]); - if ((cl.data[index_top_left_2x2_subcluster] + - cl.data[index_top_left_2x2_subcluster - ClusterSizeX]) != 0) - eta.y = static_cast( - cl.data[index_top_left_2x2_subcluster] / - (cl.data[index_top_left_2x2_subcluster] + - cl.data[index_top_left_2x2_subcluster - ClusterSizeX])); + if ((cl.data[index_bottom_left_max_2x2_subcluster] + + cl.data[index_bottom_left_max_2x2_subcluster + ClusterSizeX]) != 0) + eta.y = + static_cast( + cl.data[index_bottom_left_max_2x2_subcluster + ClusterSizeX]) / + (cl.data[index_bottom_left_max_2x2_subcluster] + + cl.data[index_bottom_left_max_2x2_subcluster + ClusterSizeX]); eta.c = c; // TODO only supported for 2x2 and 3x3 clusters -> at least no // underyling enum class @@ -446,6 +445,7 @@ Eta2 calculate_eta2( * @brief Calculate the eta2 values for a 3x3 cluster and return them in a Eta2 * struct containing etay, etax and the corner of the cluster. */ +/* template Eta2 calculate_eta2(const Cluster &cl) { Eta2 eta{}; @@ -489,7 +489,9 @@ template Eta2 calculate_eta2(const Cluster &cl) { } return eta; } +*/ +/* template Eta2 calculate_eta2(const Cluster &cl) { Eta2 eta{}; @@ -499,6 +501,7 @@ template Eta2 calculate_eta2(const Cluster &cl) { eta.c = cBottomLeft; // TODO! This is not correct, but need to put something return eta; } +*/ // TODO complicated API simplify? int analyze_cluster(Cluster &cl, int32_t *t2, int32_t *t3, diff --git a/src/Cluster.test.cpp b/src/Cluster.test.cpp new file mode 100644 index 0000000..de53e6e --- /dev/null +++ b/src/Cluster.test.cpp @@ -0,0 +1,65 @@ +/************************************************ + * @file test-Cluster.cpp + * @short test case for generic Cluster, ClusterVector, and calculate_eta2 + ***********************************************/ + +#include "aare/Cluster.hpp" +#include "aare/ClusterFile.hpp" + +// #include "catch.hpp" +#include +#include +#include + +using namespace aare; + +/* +TEST_CASE("Correct Instantiation of Cluster and ClusterVector", + "[.cluster][.instantiation]") { + + + REQUIRE(not std::is_constructible_v>); + + // all 1,2 and 0,4 are not defined!! + std::make_tuple(Cluster, ), + std::make_tuple(Cluster, ) + + +} +*/ + +using ClusterTypes = + std::variant, Cluster, Cluster, + Cluster, Cluster>; + +TEST_CASE("calculate_eta2", "[.cluster][.instantiation]") { + + // weird expect cluster_start to be in bottom_left corner -> row major -> + // check how its used should be an image!! + + auto [cluster, expected_eta] = GENERATE( + std::make_tuple(ClusterTypes{Cluster{0, 0, {1, 2, 3, 1}}}, + Eta2{2. / 3, 3. / 4, corner::cBottomLeft, 7}), + std::make_tuple( + ClusterTypes{Cluster{0, 0, {1, 2, 3, 4, 5, 6, 1, 2, 7}}}, + Eta2{6. / 11, 2. / 7, corner::cTopRight, 20}), + std::make_tuple(ClusterTypes{Cluster{ + 0, 0, {1, 6, 7, 6, 5, 4, 3, 2, 1, 8, 8, 9, 2, + 1, 4, 5, 6, 7, 8, 4, 1, 1, 1, 1, 1}}}, + Eta2{9. / 17, 5. / 13, 8, 28}), + std::make_tuple( + ClusterTypes{Cluster{0, 0, {1, 4, 7, 2, 5, 6, 4, 3}}}, + Eta2{7. / 11, 6. / 10, 1, 21}), + std::make_tuple( + ClusterTypes{Cluster{0, 0, {1, 3, 2, 3, 4, 2}}}, + Eta2{3. / 5, 4. / 6, 1, 11})); + + Eta2 eta = std::visit( + [](const auto &clustertype) { return calculate_eta2(clustertype); }, + cluster); + + CHECK(eta.x == expected_eta.x); + CHECK(eta.y == expected_eta.y); + CHECK(eta.c == expected_eta.c); + CHECK(eta.sum == expected_eta.sum); +} From 57bb6c71ae02ce1b190e72c3be3931d9bf979a5e Mon Sep 17 00:00:00 2001 From: AliceMazzoleni99 Date: Fri, 28 Mar 2025 14:49:55 +0100 Subject: [PATCH 08/51] ClusterSize should be larger than 1 --- include/aare/Cluster.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/aare/Cluster.hpp b/include/aare/Cluster.hpp index 74f5281..90701ea 100644 --- a/include/aare/Cluster.hpp +++ b/include/aare/Cluster.hpp @@ -16,8 +16,9 @@ namespace aare { // requires clause c++20 maybe update template && - std::is_integral_v>> + typename Enable = std::enable_if_t< + std::is_arithmetic_v && std::is_integral_v && + (ClusterSizeX > 1) && (ClusterSizeY > 1)>> struct Cluster { CoordType x; CoordType y; From ed9ef7c600324820ef3f9726d283d235d02cb60c Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Mon, 31 Mar 2025 12:26:29 +0200 Subject: [PATCH 09/51] removed analyze_cluster function as not used anymore --- include/aare/ClusterFile.hpp | 109 +++++------------------------------ 1 file changed, 16 insertions(+), 93 deletions(-) diff --git a/include/aare/ClusterFile.hpp b/include/aare/ClusterFile.hpp index 3a7dab8..836565b 100644 --- a/include/aare/ClusterFile.hpp +++ b/include/aare/ClusterFile.hpp @@ -503,111 +503,34 @@ template Eta2 calculate_eta2(const Cluster &cl) { } */ -// TODO complicated API simplify? -int analyze_cluster(Cluster &cl, int32_t *t2, int32_t *t3, - char *quad, double *eta2x, double *eta2y, double *eta3x, - double *eta3y) { +// calculates Eta3 for 3x3 cluster based on code from analyze_cluster +// TODO only supported for 3x3 Clusters +template Eta2 calculate_eta3(const Cluster &cl) { - return analyze_data(cl.data, t2, t3, quad, eta2x, eta2y, eta3x, eta3y); -} + Eta2 eta{}; -int analyze_data(int32_t *data, int32_t *t2, int32_t *t3, char *quad, - double *eta2x, double *eta2y, double *eta3x, double *eta3y) { + T sum = 0; - int ok = 1; + std::for_each(std::begin(cl.data), std::end(cl.data), + [&sum](T x) { sum += x; }); - int32_t tot2[4]; - int32_t t2max = 0; - char c = 0; - int32_t val, tot3; + eta.sum = sum; - tot3 = 0; - for (int i = 0; i < 4; i++) - tot2[i] = 0; + eta.c = corner::cBottomLeft; - for (int ix = 0; ix < 3; ix++) { - for (int iy = 0; iy < 3; iy++) { - val = data[iy * 3 + ix]; - // printf ("%d ",data[iy * 3 + ix]); - tot3 += val; - if (ix <= 1 && iy <= 1) - tot2[cBottomLeft] += val; - if (ix >= 1 && iy <= 1) - tot2[cBottomRight] += val; - if (ix <= 1 && iy >= 1) - tot2[cTopLeft] += val; - if (ix >= 1 && iy >= 1) - tot2[cTopRight] += val; - } - // printf ("\n"); - } - // printf ("\n"); + if ((cl.data[3] + cl.data[4] + cl.data[5]) != 0) - if (t2 || quad) { + eta.x = static_cast(-cl.data[3] + cl.data[3 + 2]) / - t2max = tot2[0]; - c = cBottomLeft; - for (int i = 1; i < 4; i++) { - if (tot2[i] > t2max) { - t2max = tot2[i]; - c = i; - } - } - // printf("*** %d %d %d %d -- - // %d\n",tot2[0],tot2[1],tot2[2],tot2[3],t2max); - if (quad) - *quad = c; - if (t2) - *t2 = t2max; - } + (cl.data[3] + cl.data[4] + cl.data[5]); - if (t3) - *t3 = tot3; + if ((cl.data[1] + cl.data[4] + cl.data[7]) != 0) - if (eta2x || eta2y) { - if (eta2x) - *eta2x = 0; - if (eta2y) - *eta2y = 0; - switch (c) { - case cBottomLeft: - if (eta2x && (data[3] + data[4]) != 0) - *eta2x = static_cast(data[4]) / (data[3] + data[4]); - if (eta2y && (data[1] + data[4]) != 0) - *eta2y = static_cast(data[4]) / (data[1] + data[4]); - break; - case cBottomRight: - if (eta2x && (data[2] + data[5]) != 0) - *eta2x = static_cast(data[5]) / (data[4] + data[5]); - if (eta2y && (data[1] + data[4]) != 0) - *eta2y = static_cast(data[4]) / (data[1] + data[4]); - break; - case cTopLeft: - if (eta2x && (data[7] + data[4]) != 0) - *eta2x = static_cast(data[4]) / (data[3] + data[4]); - if (eta2y && (data[7] + data[4]) != 0) - *eta2y = static_cast(data[7]) / (data[7] + data[4]); - break; - case cTopRight: - if (eta2x && t2max != 0) - *eta2x = static_cast(data[5]) / (data[5] + data[4]); - if (eta2y && t2max != 0) - *eta2y = static_cast(data[7]) / (data[7] + data[4]); - break; - default:; - } - } + eta.y = static_cast(-cl.data[1] + cl.data[2 * 3 + 1]) / - if (eta3x || eta3y) { - if (eta3x && (data[3] + data[4] + data[5]) != 0) - *eta3x = static_cast(-data[3] + data[3 + 2]) / - (data[3] + data[4] + data[5]); - if (eta3y && (data[1] + data[4] + data[7]) != 0) - *eta3y = static_cast(-data[1] + data[2 * 3 + 1]) / - (data[1] + data[4] + data[7]); - } + (cl.data[1] + cl.data[4] + cl.data[7]); - return ok; + return eta; } } // namespace aare From 7e5f91c6ecf8095117325b960d3e0154535c0bc2 Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Mon, 31 Mar 2025 17:04:57 +0200 Subject: [PATCH 10/51] added benchmark to time generalize calculate_eta - twice as long so will keep specific version for 2x2 and 3x3 clusters --- CMakeLists.txt | 10 ++-- benchmarks/CMakeLists.txt | 30 +++++++++--- benchmarks/calculateeta_benchmark.cpp | 66 +++++++++++++++++++++++++++ include/aare/ClusterFile.hpp | 5 +- 4 files changed, 95 insertions(+), 16 deletions(-) create mode 100644 benchmarks/calculateeta_benchmark.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 568d868..51ed7f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,14 +81,14 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) if(AARE_FETCH_LMFIT) #TODO! Should we fetch lmfit from the web or inlcude a tar.gz in the repo? - set(lmfit_patch git apply ${CMAKE_CURRENT_SOURCE_DIR}/patches/lmfit.patch) + #set(lmfit_patch git apply ${CMAKE_CURRENT_SOURCE_DIR}/patches/lmfit.patch) FetchContent_Declare( lmfit GIT_REPOSITORY https://jugit.fz-juelich.de/mlz/lmfit.git GIT_TAG main - PATCH_COMMAND ${lmfit_patch} - UPDATE_DISCONNECTED 1 - EXCLUDE_FROM_ALL 1 + #PATCH_COMMAND ${lmfit_patch} + #UPDATE_DISCONNECTED 1 + #EXCLUDE_FROM_ALL 1 ) #Disable what we don't need from lmfit set(BUILD_TESTING OFF CACHE BOOL "") @@ -359,7 +359,7 @@ set(SourceFiles add_library(aare_core STATIC ${SourceFiles}) target_include_directories(aare_core PUBLIC "$" - "$" + "$" PRIVATE ${lmfit_SOURCE_DIR}/lib ) diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index d083bab..699b4c6 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -1,11 +1,27 @@ -find_package(benchmark REQUIRED) -add_executable(ndarray_benchmark ndarray_benchmark.cpp) +include(FetchContent) -target_link_libraries(ndarray_benchmark benchmark::benchmark aare_core aare_compiler_flags) -# target_link_libraries(tests PRIVATE aare_core aare_compiler_flags) -set_target_properties(ndarray_benchmark PROPERTIES - RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} - # OUTPUT_NAME run_tests +FetchContent_Declare( + benchmark + GIT_REPOSITORY https://github.com/google/benchmark.git + GIT_TAG v1.8.3 # Change to the latest version if needed +) + +# Ensure Google Benchmark is built correctly +set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "" FORCE) + +FetchContent_MakeAvailable(benchmark) + +add_executable(benchmarks) + +target_sources(benchmarks PRIVATE ndarray_benchmark.cpp calculateeta_benchmark.cpp) + +# Link Google Benchmark and other necessary libraries +target_link_libraries(benchmarks PRIVATE benchmark::benchmark aare_core aare_compiler_flags) + +# Set output properties +set_target_properties(benchmarks PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} + OUTPUT_NAME run_benchmarks ) \ No newline at end of file diff --git a/benchmarks/calculateeta_benchmark.cpp b/benchmarks/calculateeta_benchmark.cpp new file mode 100644 index 0000000..dc7cd91 --- /dev/null +++ b/benchmarks/calculateeta_benchmark.cpp @@ -0,0 +1,66 @@ +#include "aare/ClusterFile.hpp" +#include + +using namespace aare; + +class ClusterFixture : public benchmark::Fixture { + public: + Cluster cluster_2x2{}; + Cluster cluster_3x3{}; + + void SetUp(::benchmark::State &state) { + int temp_data[4] = {1, 2, 3, 1}; + std::copy(std::begin(temp_data), std::end(temp_data), + std::begin(cluster_2x2.data)); + + cluster_2x2.x = 0; + cluster_2x2.y = 0; + + int temp_data2[9] = {1, 2, 3, 1, 3, 4, 5, 1, 20}; + std::copy(std::begin(temp_data2), std::end(temp_data2), + std::begin(cluster_3x3.data)); + + cluster_3x3.x = 0; + cluster_3x3.y = 0; + } + + // void TearDown(::benchmark::State& state) { + // } +}; + +BENCHMARK_F(ClusterFixture, Calculate2x2Eta)(benchmark::State &st) { + for (auto _ : st) { + // This code gets timed + Eta2 eta = calculate_eta2(cluster_2x2); + benchmark::DoNotOptimize(eta); + } +} + +// almost takes double the time +BENCHMARK_F(ClusterFixture, + CalculateGeneralEtaFor2x2Cluster)(benchmark::State &st) { + for (auto _ : st) { + // This code gets timed + Eta2 eta = calculate_eta2(cluster_2x2); + benchmark::DoNotOptimize(eta); + } +} + +BENCHMARK_F(ClusterFixture, Calculate3x3Eta)(benchmark::State &st) { + for (auto _ : st) { + // This code gets timed + Eta2 eta = calculate_eta2(cluster_3x3); + benchmark::DoNotOptimize(eta); + } +} + +// almost takes double the time +BENCHMARK_F(ClusterFixture, + CalculateGeneralEtaFor3x3Cluster)(benchmark::State &st) { + for (auto _ : st) { + // This code gets timed + Eta2 eta = calculate_eta2(cluster_3x3); + benchmark::DoNotOptimize(eta); + } +} +// BENCHMARK_MAIN(); \ No newline at end of file diff --git a/include/aare/ClusterFile.hpp b/include/aare/ClusterFile.hpp index 836565b..e9530f6 100644 --- a/include/aare/ClusterFile.hpp +++ b/include/aare/ClusterFile.hpp @@ -445,7 +445,7 @@ Eta2 calculate_eta2( * @brief Calculate the eta2 values for a 3x3 cluster and return them in a Eta2 * struct containing etay, etax and the corner of the cluster. */ -/* + template Eta2 calculate_eta2(const Cluster &cl) { Eta2 eta{}; @@ -489,9 +489,7 @@ template Eta2 calculate_eta2(const Cluster &cl) { } return eta; } -*/ -/* template Eta2 calculate_eta2(const Cluster &cl) { Eta2 eta{}; @@ -501,7 +499,6 @@ template Eta2 calculate_eta2(const Cluster &cl) { eta.c = cBottomLeft; // TODO! This is not correct, but need to put something return eta; } -*/ // calculates Eta3 for 3x3 cluster based on code from analyze_cluster // TODO only supported for 3x3 Clusters From e038bd16469a41605c0f6e7c0177c3948b83e1a7 Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Mon, 31 Mar 2025 17:35:39 +0200 Subject: [PATCH 11/51] refactored and put calculate_eta function in seperate file --- CMakeLists.txt | 4 +- benchmarks/calculateeta_benchmark.cpp | 1 + include/aare/ClusterFile.hpp | 213 -------------------------- include/aare/ClusterVector.hpp | 49 +++--- src/Interpolator.cpp | 1 + 5 files changed, 28 insertions(+), 240 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 51ed7f5..efb3a0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -307,6 +307,7 @@ endif() set(PUBLICHEADERS include/aare/ArrayExpr.hpp + include/aare/CalculateEta.hpp include/aare/Cluster.hpp #include/aare/ClusterFinder.hpp include/aare/ClusterFile.hpp @@ -331,7 +332,6 @@ set(PUBLICHEADERS include/aare/RawSubFile.hpp #include/aare/VarClusterFinder.hpp include/aare/utils/task.hpp - ) @@ -362,8 +362,6 @@ target_include_directories(aare_core PUBLIC "$" PRIVATE ${lmfit_SOURCE_DIR}/lib ) - - target_link_libraries( aare_core PUBLIC diff --git a/benchmarks/calculateeta_benchmark.cpp b/benchmarks/calculateeta_benchmark.cpp index dc7cd91..609ce89 100644 --- a/benchmarks/calculateeta_benchmark.cpp +++ b/benchmarks/calculateeta_benchmark.cpp @@ -1,3 +1,4 @@ +#include "aare/CalculateEta.hpp" #include "aare/ClusterFile.hpp" #include diff --git a/include/aare/ClusterFile.hpp b/include/aare/ClusterFile.hpp index e9530f6..289647d 100644 --- a/include/aare/ClusterFile.hpp +++ b/include/aare/ClusterFile.hpp @@ -9,40 +9,6 @@ namespace aare { -typedef enum { - cBottomLeft = 0, - cBottomRight = 1, - cTopLeft = 2, - cTopRight = 3 -} corner; - -typedef enum { - pBottomLeft = 0, - pBottom = 1, - pBottomRight = 2, - pLeft = 3, - pCenter = 4, - pRight = 5, - pTopLeft = 6, - pTop = 7, - pTopRight = 8 -} pixel; - -// TODO: maybe template this!!!!!! why int32_t???? -struct Eta2 { - double x; - double y; - int c; - int32_t sum; -}; - -struct ClusterAnalysis { - uint32_t c; - int32_t tot; - double etax; - double etay; -}; - /* Binary cluster file. Expects data to be layed out as: int32_t frame_number @@ -126,29 +92,6 @@ class ClusterFile { void close(); }; -int analyze_data(int32_t *data, int32_t *t2, int32_t *t3, char *quad, - double *eta2x, double *eta2y, double *eta3x, double *eta3y); -int analyze_cluster(Cluster &cl, int32_t *t2, int32_t *t3, - char *quad, double *eta2x, double *eta2y, double *eta3x, - double *eta3y); - -// template >> -// NDArray calculate_eta2(ClusterVector &clusters); - -// TODO: do we need rquire clauses? -// template Eta2 calculate_eta2(const Cluster &cl); - -// template Eta2 calculate_eta2(const Cluster &cl); - -// template >> -// Eta2 calculate_eta2(const ClusterType &cl); - -// template -// Eta2 calculate_eta2( -// const Cluster &cl); - template ClusterFile::ClusterFile( const std::filesystem::path &fname, size_t chunk_size, @@ -374,160 +317,4 @@ ClusterVector ClusterFile::read_frame() { return clusters; } -template >> -NDArray calculate_eta2(const ClusterVector &clusters) { - // TOTO! make work with 2x2 clusters - NDArray eta2({static_cast(clusters.size()), 2}); - - for (size_t i = 0; i < clusters.size(); i++) { - auto e = calculate_eta2(clusters.at(i)); - eta2(i, 0) = e.x; - eta2(i, 1) = e.y; - } - - return eta2; -} - -/** - * @brief Calculate the eta2 values for a generic sized cluster and return them - * in a Eta2 struct containing etay, etax and the index of the respective 2x2 - * subcluster. - */ -template -Eta2 calculate_eta2( - const Cluster &cl) { - Eta2 eta{}; - - // TODO loads of overhead for a 2x2 clsuter maybe keep 2x2 calculation - constexpr size_t num_2x2_subclusters = - (ClusterSizeX - 1) * (ClusterSizeY - 1); - std::array sum_2x2_subcluster; - for (size_t i = 0; i < ClusterSizeY - 1; ++i) { - for (size_t j = 0; j < ClusterSizeX - 1; ++j) - sum_2x2_subcluster[i * (ClusterSizeX - 1) + j] = - cl.data[i * ClusterSizeX + j] + - cl.data[i * ClusterSizeX + j + 1] + - cl.data[(i + 1) * ClusterSizeX + j] + - cl.data[(i + 1) * ClusterSizeX + j + 1]; - } - - auto c = - std::max_element(sum_2x2_subcluster.begin(), sum_2x2_subcluster.end()) - - sum_2x2_subcluster.begin(); - - eta.sum = sum_2x2_subcluster[c]; - - size_t index_bottom_left_max_2x2_subcluster = - (int(c / (ClusterSizeX - 1))) * ClusterSizeX + c % (ClusterSizeX - 1); - - if ((cl.data[index_bottom_left_max_2x2_subcluster] + - cl.data[index_bottom_left_max_2x2_subcluster + 1]) != 0) - eta.x = static_cast( - cl.data[index_bottom_left_max_2x2_subcluster + 1]) / - (cl.data[index_bottom_left_max_2x2_subcluster] + - cl.data[index_bottom_left_max_2x2_subcluster + 1]); - - if ((cl.data[index_bottom_left_max_2x2_subcluster] + - cl.data[index_bottom_left_max_2x2_subcluster + ClusterSizeX]) != 0) - eta.y = - static_cast( - cl.data[index_bottom_left_max_2x2_subcluster + ClusterSizeX]) / - (cl.data[index_bottom_left_max_2x2_subcluster] + - cl.data[index_bottom_left_max_2x2_subcluster + ClusterSizeX]); - - eta.c = c; // TODO only supported for 2x2 and 3x3 clusters -> at least no - // underyling enum class - return eta; -} - -/** - * @brief Calculate the eta2 values for a 3x3 cluster and return them in a Eta2 - * struct containing etay, etax and the corner of the cluster. - */ - -template Eta2 calculate_eta2(const Cluster &cl) { - Eta2 eta{}; - - std::array tot2; - tot2[0] = cl.data[0] + cl.data[1] + cl.data[3] + cl.data[4]; - tot2[1] = cl.data[1] + cl.data[2] + cl.data[4] + cl.data[5]; - tot2[2] = cl.data[3] + cl.data[4] + cl.data[6] + cl.data[7]; - tot2[3] = cl.data[4] + cl.data[5] + cl.data[7] + cl.data[8]; - - auto c = std::max_element(tot2.begin(), tot2.end()) - tot2.begin(); - eta.sum = tot2[c]; - switch (c) { - case cBottomLeft: - if ((cl.data[3] + cl.data[4]) != 0) - eta.x = static_cast(cl.data[4]) / (cl.data[3] + cl.data[4]); - if ((cl.data[1] + cl.data[4]) != 0) - eta.y = static_cast(cl.data[4]) / (cl.data[1] + cl.data[4]); - eta.c = cBottomLeft; - break; - case cBottomRight: - if ((cl.data[2] + cl.data[5]) != 0) - eta.x = static_cast(cl.data[5]) / (cl.data[4] + cl.data[5]); - if ((cl.data[1] + cl.data[4]) != 0) - eta.y = static_cast(cl.data[4]) / (cl.data[1] + cl.data[4]); - eta.c = cBottomRight; - break; - case cTopLeft: - if ((cl.data[7] + cl.data[4]) != 0) - eta.x = static_cast(cl.data[4]) / (cl.data[3] + cl.data[4]); - if ((cl.data[7] + cl.data[4]) != 0) - eta.y = static_cast(cl.data[7]) / (cl.data[7] + cl.data[4]); - eta.c = cTopLeft; - break; - case cTopRight: - if ((cl.data[5] + cl.data[4]) != 0) - eta.x = static_cast(cl.data[5]) / (cl.data[5] + cl.data[4]); - if ((cl.data[7] + cl.data[4]) != 0) - eta.y = static_cast(cl.data[7]) / (cl.data[7] + cl.data[4]); - eta.c = cTopRight; - break; - } - return eta; -} - -template Eta2 calculate_eta2(const Cluster &cl) { - Eta2 eta{}; - - eta.x = static_cast(cl.data[1]) / (cl.data[0] + cl.data[1]); - eta.y = static_cast(cl.data[2]) / (cl.data[0] + cl.data[2]); - eta.sum = cl.data[0] + cl.data[1] + cl.data[2] + cl.data[3]; - eta.c = cBottomLeft; // TODO! This is not correct, but need to put something - return eta; -} - -// calculates Eta3 for 3x3 cluster based on code from analyze_cluster -// TODO only supported for 3x3 Clusters -template Eta2 calculate_eta3(const Cluster &cl) { - - Eta2 eta{}; - - T sum = 0; - - std::for_each(std::begin(cl.data), std::end(cl.data), - [&sum](T x) { sum += x; }); - - eta.sum = sum; - - eta.c = corner::cBottomLeft; - - if ((cl.data[3] + cl.data[4] + cl.data[5]) != 0) - - eta.x = static_cast(-cl.data[3] + cl.data[3 + 2]) / - - (cl.data[3] + cl.data[4] + cl.data[5]); - - if ((cl.data[1] + cl.data[4] + cl.data[7]) != 0) - - eta.y = static_cast(-cl.data[1] + cl.data[2 * 3 + 1]) / - - (cl.data[1] + cl.data[4] + cl.data[7]); - - return eta; -} - } // namespace aare diff --git a/include/aare/ClusterVector.hpp b/include/aare/ClusterVector.hpp index ec0fa40..0e47b51 100644 --- a/include/aare/ClusterVector.hpp +++ b/include/aare/ClusterVector.hpp @@ -30,8 +30,7 @@ template class ClusterVector> { using value_type = T; - // size_t m_cluster_size_x; - // size_t m_cluster_size_y; + std::byte *m_data{}; size_t m_size{0}; size_t m_capacity; @@ -155,30 +154,32 @@ class ClusterVector> { * @throws std::runtime_error if the cluster size is not 3x3 * @warning Only 3x3 clusters are supported for the 2x2 sum. */ - std::vector sum_2x2() { - std::vector sums(m_size); - const size_t stride = item_size(); + /* only needed to calculate eta + std::vector sum_2x2() { + std::vector sums(m_size); + const size_t stride = item_size(); - if (ClusterSizeX != 3 || ClusterSizeY != 3) { - throw std::runtime_error( - "Only 3x3 clusters are supported for the 2x2 sum."); + if (ClusterSizeX != 3 || ClusterSizeY != 3) { + throw std::runtime_error( + "Only 3x3 clusters are supported for the 2x2 sum."); + } + std::byte *ptr = m_data + 2 * sizeof(CoordType); // skip x and y + + for (size_t i = 0; i < m_size; i++) { + std::array total; + auto T_ptr = reinterpret_cast(ptr); + total[0] = T_ptr[0] + T_ptr[1] + T_ptr[3] + T_ptr[4]; + total[1] = T_ptr[1] + T_ptr[2] + T_ptr[4] + T_ptr[5]; + total[2] = T_ptr[3] + T_ptr[4] + T_ptr[6] + T_ptr[7]; + total[3] = T_ptr[4] + T_ptr[5] + T_ptr[7] + T_ptr[8]; + + sums[i] = *std::max_element(total.begin(), total.end()); + ptr += stride; + } + + return sums; } - std::byte *ptr = m_data + 2 * sizeof(CoordType); // skip x and y - - for (size_t i = 0; i < m_size; i++) { - std::array total; - auto T_ptr = reinterpret_cast(ptr); - total[0] = T_ptr[0] + T_ptr[1] + T_ptr[3] + T_ptr[4]; - total[1] = T_ptr[1] + T_ptr[2] + T_ptr[4] + T_ptr[5]; - total[2] = T_ptr[3] + T_ptr[4] + T_ptr[6] + T_ptr[7]; - total[3] = T_ptr[4] + T_ptr[5] + T_ptr[7] + T_ptr[8]; - - sums[i] = *std::max_element(total.begin(), total.end()); - ptr += stride; - } - - return sums; - } + */ /** * @brief Return the number of clusters in the vector diff --git a/src/Interpolator.cpp b/src/Interpolator.cpp index d95405a..1c4a385 100644 --- a/src/Interpolator.cpp +++ b/src/Interpolator.cpp @@ -1,4 +1,5 @@ #include "aare/Interpolator.hpp" +#include "aare/CalculateEta.hpp" #include "aare/algorithm.hpp" namespace aare { From 508adf5016fda7c274279e43d8899ea29e003015 Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Tue, 1 Apr 2025 10:01:23 +0200 Subject: [PATCH 12/51] refactoring of remaining files --- CMakeLists.txt | 9 +- include/aare/CalculateEta.hpp | 192 +++++++++++++++++++++++++++++++++ include/aare/Cluster.hpp | 11 +- include/aare/ClusterFileV2.hpp | 28 +++-- include/aare/ClusterFinder.hpp | 51 ++++----- src/Cluster.test.cpp | 19 ++-- src/ClusterFinder.test.cpp | 24 ++--- src/ClusterVector.test.cpp | 154 ++++++++++++-------------- 8 files changed, 338 insertions(+), 150 deletions(-) create mode 100644 include/aare/CalculateEta.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index efb3a0c..0bdc317 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -309,7 +309,7 @@ set(PUBLICHEADERS include/aare/ArrayExpr.hpp include/aare/CalculateEta.hpp include/aare/Cluster.hpp - #include/aare/ClusterFinder.hpp + include/aare/ClusterFinder.hpp include/aare/ClusterFile.hpp include/aare/CtbRawFile.hpp include/aare/ClusterVector.hpp @@ -330,14 +330,13 @@ set(PUBLICHEADERS include/aare/RawFile.hpp include/aare/RawMasterFile.hpp include/aare/RawSubFile.hpp - #include/aare/VarClusterFinder.hpp + include/aare/VarClusterFinder.hpp include/aare/utils/task.hpp ) set(SourceFiles ${CMAKE_CURRENT_SOURCE_DIR}/src/CtbRawFile.cpp - #${CMAKE_CURRENT_SOURCE_DIR}/src/ClusterFile.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/defs.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Dtype.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/decode.cpp @@ -393,8 +392,8 @@ if(AARE_TESTS) ${CMAKE_CURRENT_SOURCE_DIR}/src/RawMasterFile.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/NDArray.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/NDView.test.cpp - #${CMAKE_CURRENT_SOURCE_DIR}/src/ClusterFinder.test.cpp - #${CMAKE_CURRENT_SOURCE_DIR}/src/ClusterVector.test.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ClusterFinder.test.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ClusterVector.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Cluster.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Pedestal.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/NumpyFile.test.cpp diff --git a/include/aare/CalculateEta.hpp b/include/aare/CalculateEta.hpp new file mode 100644 index 0000000..29c5cc4 --- /dev/null +++ b/include/aare/CalculateEta.hpp @@ -0,0 +1,192 @@ +#pragma once + +#include "aare/Cluster.hpp" +#include "aare/ClusterVector.hpp" +#include "aare/NDArray.hpp" + +namespace aare { + +typedef enum { + cBottomLeft = 0, + cBottomRight = 1, + cTopLeft = 2, + cTopRight = 3 +} corner; + +typedef enum { + pBottomLeft = 0, + pBottom = 1, + pBottomRight = 2, + pLeft = 3, + pCenter = 4, + pRight = 5, + pTopLeft = 6, + pTop = 7, + pTopRight = 8 +} pixel; + +// TODO: maybe template this!!!!!! why int32_t???? +struct Eta2 { + double x; + double y; + int c; + int32_t sum; +}; + +/** + * @brief Calculate the eta2 values for all clusters in a Clsutervector + */ +template >> +NDArray calculate_eta2(const ClusterVector &clusters) { + NDArray eta2({static_cast(clusters.size()), 2}); + + for (size_t i = 0; i < clusters.size(); i++) { + auto e = calculate_eta2(clusters.at(i)); + eta2(i, 0) = e.x; + eta2(i, 1) = e.y; + } + + return eta2; +} + +/** + * @brief Calculate the eta2 values for a generic sized cluster and return them + * in a Eta2 struct containing etay, etax and the index of the respective 2x2 + * subcluster. + */ +template +Eta2 calculate_eta2( + const Cluster &cl) { + Eta2 eta{}; + + constexpr size_t num_2x2_subclusters = + (ClusterSizeX - 1) * (ClusterSizeY - 1); + std::array sum_2x2_subcluster; + for (size_t i = 0; i < ClusterSizeY - 1; ++i) { + for (size_t j = 0; j < ClusterSizeX - 1; ++j) + sum_2x2_subcluster[i * (ClusterSizeX - 1) + j] = + cl.data[i * ClusterSizeX + j] + + cl.data[i * ClusterSizeX + j + 1] + + cl.data[(i + 1) * ClusterSizeX + j] + + cl.data[(i + 1) * ClusterSizeX + j + 1]; + } + + auto c = + std::max_element(sum_2x2_subcluster.begin(), sum_2x2_subcluster.end()) - + sum_2x2_subcluster.begin(); + + eta.sum = sum_2x2_subcluster[c]; + + size_t index_bottom_left_max_2x2_subcluster = + (int(c / (ClusterSizeX - 1))) * ClusterSizeX + c % (ClusterSizeX - 1); + + if ((cl.data[index_bottom_left_max_2x2_subcluster] + + cl.data[index_bottom_left_max_2x2_subcluster + 1]) != 0) + eta.x = static_cast( + cl.data[index_bottom_left_max_2x2_subcluster + 1]) / + (cl.data[index_bottom_left_max_2x2_subcluster] + + cl.data[index_bottom_left_max_2x2_subcluster + 1]); + + if ((cl.data[index_bottom_left_max_2x2_subcluster] + + cl.data[index_bottom_left_max_2x2_subcluster + ClusterSizeX]) != 0) + eta.y = + static_cast( + cl.data[index_bottom_left_max_2x2_subcluster + ClusterSizeX]) / + (cl.data[index_bottom_left_max_2x2_subcluster] + + cl.data[index_bottom_left_max_2x2_subcluster + ClusterSizeX]); + + eta.c = c; // TODO only supported for 2x2 and 3x3 clusters -> at least no + // underyling enum class + return eta; +} + +/** + * @brief Calculate the eta2 values for a 3x3 cluster and return them in a Eta2 + * struct containing etay, etax and the corner of the cluster. + */ +template Eta2 calculate_eta2(const Cluster &cl) { + Eta2 eta{}; + + std::array tot2; + tot2[0] = cl.data[0] + cl.data[1] + cl.data[3] + cl.data[4]; + tot2[1] = cl.data[1] + cl.data[2] + cl.data[4] + cl.data[5]; + tot2[2] = cl.data[3] + cl.data[4] + cl.data[6] + cl.data[7]; + tot2[3] = cl.data[4] + cl.data[5] + cl.data[7] + cl.data[8]; + + auto c = std::max_element(tot2.begin(), tot2.end()) - tot2.begin(); + eta.sum = tot2[c]; + switch (c) { + case cBottomLeft: + if ((cl.data[3] + cl.data[4]) != 0) + eta.x = static_cast(cl.data[4]) / (cl.data[3] + cl.data[4]); + if ((cl.data[1] + cl.data[4]) != 0) + eta.y = static_cast(cl.data[4]) / (cl.data[1] + cl.data[4]); + eta.c = cBottomLeft; + break; + case cBottomRight: + if ((cl.data[2] + cl.data[5]) != 0) + eta.x = static_cast(cl.data[5]) / (cl.data[4] + cl.data[5]); + if ((cl.data[1] + cl.data[4]) != 0) + eta.y = static_cast(cl.data[4]) / (cl.data[1] + cl.data[4]); + eta.c = cBottomRight; + break; + case cTopLeft: + if ((cl.data[7] + cl.data[4]) != 0) + eta.x = static_cast(cl.data[4]) / (cl.data[3] + cl.data[4]); + if ((cl.data[7] + cl.data[4]) != 0) + eta.y = static_cast(cl.data[7]) / (cl.data[7] + cl.data[4]); + eta.c = cTopLeft; + break; + case cTopRight: + if ((cl.data[5] + cl.data[4]) != 0) + eta.x = static_cast(cl.data[5]) / (cl.data[5] + cl.data[4]); + if ((cl.data[7] + cl.data[4]) != 0) + eta.y = static_cast(cl.data[7]) / (cl.data[7] + cl.data[4]); + eta.c = cTopRight; + break; + } + return eta; +} + +template Eta2 calculate_eta2(const Cluster &cl) { + Eta2 eta{}; + + eta.x = static_cast(cl.data[1]) / (cl.data[0] + cl.data[1]); + eta.y = static_cast(cl.data[2]) / (cl.data[0] + cl.data[2]); + eta.sum = cl.data[0] + cl.data[1] + cl.data[2] + cl.data[3]; + eta.c = cBottomLeft; // TODO! This is not correct, but need to put something + return eta; +} + +// calculates Eta3 for 3x3 cluster based on code from analyze_cluster +// TODO only supported for 3x3 Clusters +template Eta2 calculate_eta3(const Cluster &cl) { + + Eta2 eta{}; + + T sum = 0; + + std::for_each(std::begin(cl.data), std::end(cl.data), + [&sum](T x) { sum += x; }); + + eta.sum = sum; + + eta.c = corner::cBottomLeft; + + if ((cl.data[3] + cl.data[4] + cl.data[5]) != 0) + + eta.x = static_cast(-cl.data[3] + cl.data[3 + 2]) / + + (cl.data[3] + cl.data[4] + cl.data[5]); + + if ((cl.data[1] + cl.data[4] + cl.data[7]) != 0) + + eta.y = static_cast(-cl.data[1] + cl.data[2 * 3 + 1]) / + + (cl.data[1] + cl.data[4] + cl.data[7]); + + return eta; +} + +} // namespace aare \ No newline at end of file diff --git a/include/aare/Cluster.hpp b/include/aare/Cluster.hpp index 90701ea..b2d1d3c 100644 --- a/include/aare/Cluster.hpp +++ b/include/aare/Cluster.hpp @@ -13,12 +13,17 @@ namespace aare { +template +constexpr bool is_valid_cluster = + std::is_arithmetic_v && std::is_integral_v && + (ClusterSizeX > 0) && (ClusterSizeY > 0); + // requires clause c++20 maybe update template && std::is_integral_v && - (ClusterSizeX > 1) && (ClusterSizeY > 1)>> + is_valid_cluster>> struct Cluster { CoordType x; CoordType y; @@ -29,11 +34,9 @@ struct Cluster { template struct is_cluster : std::false_type {}; // Default case: Not a Cluster -// TODO: Do i need the require clause here as well? template struct is_cluster> : std::true_type {}; // Cluster -// helper template constexpr bool is_cluster_v = is_cluster::value; } // namespace aare diff --git a/include/aare/ClusterFileV2.hpp b/include/aare/ClusterFileV2.hpp index 99f5976..55b8a2b 100644 --- a/include/aare/ClusterFileV2.hpp +++ b/include/aare/ClusterFileV2.hpp @@ -1,15 +1,16 @@ #pragma once #include "aare/core/defs.hpp" #include -#include #include +#include namespace aare { struct ClusterHeader { int32_t frame_number; int32_t n_clusters; std::string to_string() const { - return "frame_number: " + std::to_string(frame_number) + ", n_clusters: " + std::to_string(n_clusters); + return "frame_number: " + std::to_string(frame_number) + + ", n_clusters: " + std::to_string(n_clusters); } }; @@ -24,7 +25,8 @@ struct ClusterV2_ { data_str += std::to_string(d) + ", "; } data_str += "]"; - return "x: " + std::to_string(x) + ", y: " + std::to_string(y) + ", data: " + data_str; + return "x: " + std::to_string(x) + ", y: " + std::to_string(y) + + ", data: " + data_str; } return "x: " + std::to_string(x) + ", y: " + std::to_string(y); } @@ -34,27 +36,31 @@ struct ClusterV2 { ClusterV2_ cluster; int32_t frame_number; std::string to_string() const { - return "frame_number: " + std::to_string(frame_number) + ", " + cluster.to_string(); + return "frame_number: " + std::to_string(frame_number) + ", " + + cluster.to_string(); } }; /** * @brief - * important not: fp always points to the clusters header and does not point to individual clusters + * important not: fp always points to the clusters header and does not point to + * individual clusters * */ class ClusterFileV2 { - std::filesystem::path m_fpath; + std::filesystem::path m_fpath; std::string m_mode; FILE *fp{nullptr}; - void check_open(){ + void check_open() { if (!fp) - throw std::runtime_error(fmt::format("File: {} not open", m_fpath.string())); + throw std::runtime_error( + fmt::format("File: {} not open", m_fpath.string())); } public: - ClusterFileV2(std::filesystem::path const &fpath, std::string const &mode): m_fpath(fpath), m_mode(mode) { + ClusterFileV2(std::filesystem::path const &fpath, std::string const &mode) + : m_fpath(fpath), m_mode(mode) { if (m_mode != "r" && m_mode != "w") throw std::invalid_argument("mode must be 'r' or 'w'"); if (m_mode == "r" && !std::filesystem::exists(m_fpath)) @@ -77,7 +83,7 @@ class ClusterFileV2 { check_open(); ClusterHeader header; - fread(&header, sizeof(ClusterHeader), 1, fp); + fread(&header, sizeof(ClusterHeader), 1, fp); std::vector clusters_(header.n_clusters); fread(clusters_.data(), sizeof(ClusterV2_), header.n_clusters, fp); std::vector clusters; @@ -117,7 +123,7 @@ class ClusterFileV2 { size_t write(std::vector> const &clusters) { check_open(); - if (m_mode != "w") + if (m_mode != "w") throw std::runtime_error("File not opened in write mode"); size_t n_clusters = 0; diff --git a/include/aare/ClusterFinder.hpp b/include/aare/ClusterFinder.hpp index 84b207b..9a15448 100644 --- a/include/aare/ClusterFinder.hpp +++ b/include/aare/ClusterFinder.hpp @@ -10,17 +10,16 @@ namespace aare { -template +template class ClusterFinder { Shape<2> m_image_size; - const int m_cluster_sizeX; - const int m_cluster_sizeY; const PEDESTAL_TYPE m_nSigma; const PEDESTAL_TYPE c2; const PEDESTAL_TYPE c3; Pedestal m_pedestal; - ClusterVector m_clusters; + ClusterVector> m_clusters; public: /** @@ -31,15 +30,12 @@ class ClusterFinder { * @param capacity initial capacity of the cluster vector * */ - ClusterFinder(Shape<2> image_size, Shape<2> cluster_size, - PEDESTAL_TYPE nSigma = 5.0, size_t capacity = 1000000) - : m_image_size(image_size), m_cluster_sizeX(cluster_size[0]), - m_cluster_sizeY(cluster_size[1]), - m_nSigma(nSigma), - c2(sqrt((m_cluster_sizeY + 1) / 2 * (m_cluster_sizeX + 1) / 2)), - c3(sqrt(m_cluster_sizeX * m_cluster_sizeY)), - m_pedestal(image_size[0], image_size[1]), - m_clusters(m_cluster_sizeX, m_cluster_sizeY, capacity) {}; + ClusterFinder(Shape<2> image_size, PEDESTAL_TYPE nSigma = 5.0, + size_t capacity = 1000000) + : m_image_size(image_size), m_nSigma(nSigma), + c2(sqrt((ClusterSizeY + 1) / 2 * (ClusterSizeX + 1) / 2)), + c3(sqrt(ClusterSizeX * ClusterSizeY)), + m_pedestal(image_size[0], image_size[1]), m_clusters(capacity) {}; void push_pedestal_frame(NDView frame) { m_pedestal.push(frame); @@ -56,23 +52,26 @@ class ClusterFinder { * same capacity as the old one * */ - ClusterVector steal_clusters(bool realloc_same_capacity = false) { - ClusterVector tmp = std::move(m_clusters); + ClusterVector> + steal_clusters(bool realloc_same_capacity = false) { + ClusterVector> tmp = + std::move(m_clusters); if (realloc_same_capacity) - m_clusters = ClusterVector(m_cluster_sizeX, m_cluster_sizeY, - tmp.capacity()); + m_clusters = ClusterVector>( + tmp.capacity()); else - m_clusters = ClusterVector(m_cluster_sizeX, m_cluster_sizeY); + m_clusters = + ClusterVector>{}; return tmp; } void find_clusters(NDView frame, uint64_t frame_number = 0) { // // TODO! deal with even size clusters // // currently 3,3 -> +/- 1 // // 4,4 -> +/- 2 - int dy = m_cluster_sizeY / 2; - int dx = m_cluster_sizeX / 2; + int dy = ClusterSizeY / 2; + int dx = ClusterSizeX / 2; m_clusters.set_frame_number(frame_number); - std::vector cluster_data(m_cluster_sizeX * m_cluster_sizeY); + std::vector cluster_data(ClusterSizeX * ClusterSizeY); for (int iy = 0; iy < frame.shape(0); iy++) { for (int ix = 0; ix < frame.shape(1); ix++) { @@ -109,8 +108,12 @@ class ClusterFinder { // pass } else { // m_pedestal.push(iy, ix, frame(iy, ix)); // Safe option - 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 + 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 diff --git a/src/Cluster.test.cpp b/src/Cluster.test.cpp index de53e6e..20c3948 100644 --- a/src/Cluster.test.cpp +++ b/src/Cluster.test.cpp @@ -4,6 +4,7 @@ ***********************************************/ #include "aare/Cluster.hpp" +#include "aare/CalculateEta.hpp" #include "aare/ClusterFile.hpp" // #include "catch.hpp" @@ -13,26 +14,24 @@ using namespace aare; -/* TEST_CASE("Correct Instantiation of Cluster and ClusterVector", "[.cluster][.instantiation]") { + CHECK(is_valid_cluster); + CHECK(is_valid_cluster); + CHECK(not is_valid_cluster); + CHECK(not is_valid_cluster); + CHECK(not is_valid_cluster); - REQUIRE(not std::is_constructible_v>); - - // all 1,2 and 0,4 are not defined!! - std::make_tuple(Cluster, ), - std::make_tuple(Cluster, ) - - + CHECK(not is_cluster_v); + CHECK(is_cluster_v>); } -*/ using ClusterTypes = std::variant, Cluster, Cluster, Cluster, Cluster>; -TEST_CASE("calculate_eta2", "[.cluster][.instantiation]") { +TEST_CASE("calculate_eta2", "[.cluster][.eta_calculation]") { // weird expect cluster_start to be in bottom_left corner -> row major -> // check how its used should be an image!! diff --git a/src/ClusterFinder.test.cpp b/src/ClusterFinder.test.cpp index 768e632..8989581 100644 --- a/src/ClusterFinder.test.cpp +++ b/src/ClusterFinder.test.cpp @@ -1,19 +1,18 @@ #include "aare/ClusterFinder.hpp" #include "aare/Pedestal.hpp" -#include #include +#include #include #include using namespace aare; -//TODO! Find a way to test the cluster finder - - +// TODO! Find a way to test the cluster finder // class ClusterFinderUnitTest : public ClusterFinder { // public: -// ClusterFinderUnitTest(int cluster_sizeX, int cluster_sizeY, double nSigma = 5.0, double threshold = 0.0) +// ClusterFinderUnitTest(int cluster_sizeX, int cluster_sizeY, double nSigma +// = 5.0, double threshold = 0.0) // : ClusterFinder(cluster_sizeX, cluster_sizeY, nSigma, threshold) {} // double get_c2() { return c2; } // double get_c3() { return c3; } @@ -37,8 +36,8 @@ using namespace aare; // REQUIRE_THAT(cf.get_c3(), Catch::Matchers::WithinRel(c3, 1e-9)); // } -TEST_CASE("Construct a cluster finder"){ - ClusterFinder clusterFinder({400,400}, {3,3}); +TEST_CASE("Construct a cluster finder") { + ClusterFinder clusterFinder({400, 400}); // REQUIRE(clusterFinder.get_cluster_sizeX() == 3); // REQUIRE(clusterFinder.get_cluster_sizeY() == 3); // REQUIRE(clusterFinder.get_threshold() == 1); @@ -49,16 +48,17 @@ TEST_CASE("Construct a cluster finder"){ // aare::Pedestal pedestal(10, 10, 5); // NDArray frame({10, 10}); // frame = 0; -// ClusterFinder clusterFinder(3, 3, 1, 1); // 3x3 cluster, 1 nSigma, 1 threshold +// ClusterFinder clusterFinder(3, 3, 1, 1); // 3x3 cluster, 1 nSigma, 1 +// threshold -// auto clusters = clusterFinder.find_clusters_without_threshold(frame.span(), pedestal); +// auto clusters = +// clusterFinder.find_clusters_without_threshold(frame.span(), pedestal); // REQUIRE(clusters.size() == 0); // frame(5, 5) = 10; -// clusters = clusterFinder.find_clusters_without_threshold(frame.span(), pedestal); -// REQUIRE(clusters.size() == 1); -// REQUIRE(clusters[0].x == 5); +// clusters = clusterFinder.find_clusters_without_threshold(frame.span(), +// pedestal); REQUIRE(clusters.size() == 1); REQUIRE(clusters[0].x == 5); // REQUIRE(clusters[0].y == 5); // for (int i = 0; i < 3; i++) { // for (int j = 0; j < 3; j++) { diff --git a/src/ClusterVector.test.cpp b/src/ClusterVector.test.cpp index 8ca3b1e..acbbf56 100644 --- a/src/ClusterVector.test.cpp +++ b/src/ClusterVector.test.cpp @@ -1,21 +1,15 @@ -#include #include "aare/ClusterVector.hpp" +#include -#include #include +#include +using aare::Cluster; using aare::ClusterVector; -struct Cluster_i2x2 { - int16_t x; - int16_t y; - int32_t data[4]; -}; - TEST_CASE("ClusterVector 2x2 int32_t capacity 4, push back then read") { - - ClusterVector cv(2, 2, 4); + ClusterVector> cv(4); REQUIRE(cv.capacity() == 4); REQUIRE(cv.size() == 0); REQUIRE(cv.cluster_size_x() == 2); @@ -23,51 +17,45 @@ TEST_CASE("ClusterVector 2x2 int32_t capacity 4, push back then read") { // int16_t, int16_t, 2x2 int32_t = 20 bytes REQUIRE(cv.item_size() == 20); - //Create a cluster and push back into the vector - Cluster_i2x2 c1 = {1, 2, {3, 4, 5, 6}}; - cv.push_back(c1.x, c1.y, reinterpret_cast(&c1.data[0])); + // Create a cluster and push back into the vector + Cluster c1 = {1, 2, {3, 4, 5, 6}}; + cv.push_back(c1.x, c1.y, reinterpret_cast(&c1.data[0])); REQUIRE(cv.size() == 1); REQUIRE(cv.capacity() == 4); - //Read the cluster back out using copy. TODO! Can we improve the API? - Cluster_i2x2 c2; + // Read the cluster back out using copy. TODO! Can we improve the API? + Cluster c2; std::byte *ptr = cv.element_ptr(0); - std::copy(ptr, ptr + cv.item_size(), reinterpret_cast(&c2)); + std::copy(ptr, ptr + cv.item_size(), reinterpret_cast(&c2)); - //Check that the data is the same + // Check that the data is the same REQUIRE(c1.x == c2.x); REQUIRE(c1.y == c2.y); - for(size_t i = 0; i < 4; i++) { + for (size_t i = 0; i < 4; i++) { REQUIRE(c1.data[i] == c2.data[i]); } } -TEST_CASE("Summing 3x1 clusters of int64"){ - struct Cluster_l3x1{ - int16_t x; - int16_t y; - int32_t data[3]; - }; - - ClusterVector cv(3, 1, 2); +TEST_CASE("Summing 3x1 clusters of int64") { + ClusterVector> cv(2); REQUIRE(cv.capacity() == 2); REQUIRE(cv.size() == 0); REQUIRE(cv.cluster_size_x() == 3); REQUIRE(cv.cluster_size_y() == 1); - //Create a cluster and push back into the vector - Cluster_l3x1 c1 = {1, 2, {3, 4, 5}}; - cv.push_back(c1.x, c1.y, reinterpret_cast(&c1.data[0])); + // Create a cluster and push back into the vector + Cluster c1 = {1, 2, {3, 4, 5}}; + cv.push_back(c1.x, c1.y, reinterpret_cast(&c1.data[0])); REQUIRE(cv.capacity() == 2); REQUIRE(cv.size() == 1); - Cluster_l3x1 c2 = {6, 7, {8, 9, 10}}; - cv.push_back(c2.x, c2.y, reinterpret_cast(&c2.data[0])); + Cluster c2 = {6, 7, {8, 9, 10}}; + cv.push_back(c2.x, c2.y, reinterpret_cast(&c2.data[0])); REQUIRE(cv.capacity() == 2); REQUIRE(cv.size() == 2); - Cluster_l3x1 c3 = {11, 12, {13, 14, 15}}; - cv.push_back(c3.x, c3.y, reinterpret_cast(&c3.data[0])); + Cluster c3 = {11, 12, {13, 14, 15}}; + cv.push_back(c3.x, c3.y, reinterpret_cast(&c3.data[0])); REQUIRE(cv.capacity() == 4); REQUIRE(cv.size() == 3); @@ -78,28 +66,22 @@ TEST_CASE("Summing 3x1 clusters of int64"){ REQUIRE(sums[2] == 42); } -TEST_CASE("Storing floats"){ - struct Cluster_f4x2{ - int16_t x; - int16_t y; - float data[8]; - }; - - ClusterVector cv(2, 4, 10); +TEST_CASE("Storing floats") { + ClusterVector> cv(10); REQUIRE(cv.capacity() == 10); REQUIRE(cv.size() == 0); REQUIRE(cv.cluster_size_x() == 2); REQUIRE(cv.cluster_size_y() == 4); - //Create a cluster and push back into the vector - Cluster_f4x2 c1 = {1, 2, {3.0, 4.0, 5.0, 6.0,3.0, 4.0, 5.0, 6.0}}; - cv.push_back(c1.x, c1.y, reinterpret_cast(&c1.data[0])); + // Create a cluster and push back into the vector + Cluster c1 = {1, 2, {3.0, 4.0, 5.0, 6.0, 3.0, 4.0, 5.0, 6.0}}; + cv.push_back(c1.x, c1.y, reinterpret_cast(&c1.data[0])); REQUIRE(cv.capacity() == 10); REQUIRE(cv.size() == 1); - - Cluster_f4x2 c2 = {6, 7, {8.0, 9.0, 10.0, 11.0,8.0, 9.0, 10.0, 11.0}}; - cv.push_back(c2.x, c2.y, reinterpret_cast(&c2.data[0])); + Cluster c2 = { + 6, 7, {8.0, 9.0, 10.0, 11.0, 8.0, 9.0, 10.0, 11.0}}; + cv.push_back(c2.x, c2.y, reinterpret_cast(&c2.data[0])); REQUIRE(cv.capacity() == 10); REQUIRE(cv.size() == 2); @@ -109,26 +91,27 @@ TEST_CASE("Storing floats"){ REQUIRE_THAT(sums[1], Catch::Matchers::WithinAbs(76.0, 1e-6)); } -TEST_CASE("Push back more than initial capacity"){ - - ClusterVector cv(2, 2, 2); +TEST_CASE("Push back more than initial capacity") { + + ClusterVector> cv(2); auto initial_data = cv.data(); - Cluster_i2x2 c1 = {1, 2, {3, 4, 5, 6}}; - cv.push_back(c1.x, c1.y, reinterpret_cast(&c1.data[0])); + Cluster c1 = {1, 2, {3, 4, 5, 6}}; + cv.push_back(c1.x, c1.y, reinterpret_cast(&c1.data[0])); REQUIRE(cv.size() == 1); REQUIRE(cv.capacity() == 2); - Cluster_i2x2 c2 = {6, 7, {8, 9, 10, 11}}; - cv.push_back(c2.x, c2.y, reinterpret_cast(&c2.data[0])); + Cluster c2 = {6, 7, {8, 9, 10, 11}}; + cv.push_back(c2.x, c2.y, reinterpret_cast(&c2.data[0])); REQUIRE(cv.size() == 2); REQUIRE(cv.capacity() == 2); - Cluster_i2x2 c3 = {11, 12, {13, 14, 15, 16}}; - cv.push_back(c3.x, c3.y, reinterpret_cast(&c3.data[0])); - REQUIRE(cv.size() == 3); + Cluster c3 = {11, 12, {13, 14, 15, 16}}; + cv.push_back(c3.x, c3.y, reinterpret_cast(&c3.data[0])); + REQUIRE(cv.size() == 3); REQUIRE(cv.capacity() == 4); - Cluster_i2x2* ptr = reinterpret_cast(cv.data()); + Cluster *ptr = + reinterpret_cast *>(cv.data()); REQUIRE(ptr[0].x == 1); REQUIRE(ptr[0].y == 2); REQUIRE(ptr[1].x == 6); @@ -136,29 +119,31 @@ TEST_CASE("Push back more than initial capacity"){ REQUIRE(ptr[2].x == 11); REQUIRE(ptr[2].y == 12); - //We should have allocated a new buffer, since we outgrew the initial capacity + // We should have allocated a new buffer, since we outgrew the initial + // capacity REQUIRE(initial_data != cv.data()); - } -TEST_CASE("Concatenate two cluster vectors where the first has enough capacity"){ - ClusterVector cv1(2, 2, 12); - Cluster_i2x2 c1 = {1, 2, {3, 4, 5, 6}}; - cv1.push_back(c1.x, c1.y, reinterpret_cast(&c1.data[0])); - Cluster_i2x2 c2 = {6, 7, {8, 9, 10, 11}}; - cv1.push_back(c2.x, c2.y, reinterpret_cast(&c2.data[0])); +TEST_CASE( + "Concatenate two cluster vectors where the first has enough capacity") { + ClusterVector> cv1(12); + Cluster c1 = {1, 2, {3, 4, 5, 6}}; + cv1.push_back(c1.x, c1.y, reinterpret_cast(&c1.data[0])); + Cluster c2 = {6, 7, {8, 9, 10, 11}}; + cv1.push_back(c2.x, c2.y, reinterpret_cast(&c2.data[0])); - ClusterVector cv2(2, 2, 2); - Cluster_i2x2 c3 = {11, 12, {13, 14, 15, 16}}; - cv2.push_back(c3.x, c3.y, reinterpret_cast(&c3.data[0])); - Cluster_i2x2 c4 = {16, 17, {18, 19, 20, 21}}; - cv2.push_back(c4.x, c4.y, reinterpret_cast(&c4.data[0])); + ClusterVector> cv2(2); + Cluster c3 = {11, 12, {13, 14, 15, 16}}; + cv2.push_back(c3.x, c3.y, reinterpret_cast(&c3.data[0])); + Cluster c4 = {16, 17, {18, 19, 20, 21}}; + cv2.push_back(c4.x, c4.y, reinterpret_cast(&c4.data[0])); cv1 += cv2; REQUIRE(cv1.size() == 4); REQUIRE(cv1.capacity() == 12); - Cluster_i2x2* ptr = reinterpret_cast(cv1.data()); + Cluster *ptr = + reinterpret_cast *>(cv1.data()); REQUIRE(ptr[0].x == 1); REQUIRE(ptr[0].y == 2); REQUIRE(ptr[1].x == 6); @@ -169,24 +154,25 @@ TEST_CASE("Concatenate two cluster vectors where the first has enough capacity") REQUIRE(ptr[3].y == 17); } -TEST_CASE("Concatenate two cluster vectors where we need to allocate"){ - ClusterVector cv1(2, 2, 2); - Cluster_i2x2 c1 = {1, 2, {3, 4, 5, 6}}; - cv1.push_back(c1.x, c1.y, reinterpret_cast(&c1.data[0])); - Cluster_i2x2 c2 = {6, 7, {8, 9, 10, 11}}; - cv1.push_back(c2.x, c2.y, reinterpret_cast(&c2.data[0])); +TEST_CASE("Concatenate two cluster vectors where we need to allocate") { + ClusterVector> cv1(2); + Cluster c1 = {1, 2, {3, 4, 5, 6}}; + cv1.push_back(c1.x, c1.y, reinterpret_cast(&c1.data[0])); + Cluster c2 = {6, 7, {8, 9, 10, 11}}; + cv1.push_back(c2.x, c2.y, reinterpret_cast(&c2.data[0])); - ClusterVector cv2(2, 2, 2); - Cluster_i2x2 c3 = {11, 12, {13, 14, 15, 16}}; - cv2.push_back(c3.x, c3.y, reinterpret_cast(&c3.data[0])); - Cluster_i2x2 c4 = {16, 17, {18, 19, 20, 21}}; - cv2.push_back(c4.x, c4.y, reinterpret_cast(&c4.data[0])); + ClusterVector> cv2(2); + Cluster c3 = {11, 12, {13, 14, 15, 16}}; + cv2.push_back(c3.x, c3.y, reinterpret_cast(&c3.data[0])); + Cluster c4 = {16, 17, {18, 19, 20, 21}}; + cv2.push_back(c4.x, c4.y, reinterpret_cast(&c4.data[0])); cv1 += cv2; REQUIRE(cv1.size() == 4); REQUIRE(cv1.capacity() == 4); - Cluster_i2x2* ptr = reinterpret_cast(cv1.data()); + Cluster *ptr = + reinterpret_cast *>(cv1.data()); REQUIRE(ptr[0].x == 1); REQUIRE(ptr[0].y == 2); REQUIRE(ptr[1].x == 6); From 745d09fbe901c9c07d5d3e6fc80d7366ff057957 Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Tue, 1 Apr 2025 15:30:10 +0200 Subject: [PATCH 13/51] changed push_back to take Cluster as input argument --- CMakeLists.txt | 10 +++---- include/aare/ClusterFile.hpp | 12 ++++---- include/aare/ClusterFinder.hpp | 5 ++++ include/aare/ClusterVector.hpp | 22 ++++++--------- src/ClusterVector.test.cpp | 50 ++++++++++++++++++---------------- src/Interpolator.cpp | 2 ++ 6 files changed, 54 insertions(+), 47 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0bdc317..9e02a8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,13 +81,13 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) if(AARE_FETCH_LMFIT) #TODO! Should we fetch lmfit from the web or inlcude a tar.gz in the repo? - #set(lmfit_patch git apply ${CMAKE_CURRENT_SOURCE_DIR}/patches/lmfit.patch) + set(lmfit_patch git apply ${CMAKE_CURRENT_SOURCE_DIR}/patches/lmfit.patch) FetchContent_Declare( lmfit GIT_REPOSITORY https://jugit.fz-juelich.de/mlz/lmfit.git GIT_TAG main - #PATCH_COMMAND ${lmfit_patch} - #UPDATE_DISCONNECTED 1 + PATCH_COMMAND ${lmfit_patch} + UPDATE_DISCONNECTED 1 #EXCLUDE_FROM_ALL 1 ) #Disable what we don't need from lmfit @@ -358,7 +358,7 @@ set(SourceFiles add_library(aare_core STATIC ${SourceFiles}) target_include_directories(aare_core PUBLIC "$" - "$" PRIVATE ${lmfit_SOURCE_DIR}/lib + "$" ) target_link_libraries( @@ -369,7 +369,7 @@ target_link_libraries( ${STD_FS_LIB} # from helpers.cmake PRIVATE aare_compiler_flags - "$" + $ ) diff --git a/include/aare/ClusterFile.hpp b/include/aare/ClusterFile.hpp index 289647d..6bd231e 100644 --- a/include/aare/ClusterFile.hpp +++ b/include/aare/ClusterFile.hpp @@ -243,8 +243,9 @@ ClusterFile::read_clusters(size_t n_clusters, ROI roi) { fread(&tmp, sizeof(tmp), 1, fp); if (tmp.x >= roi.xmin && tmp.x <= roi.xmax && tmp.y >= roi.ymin && tmp.y <= roi.ymax) { - clusters.push_back(tmp.x, tmp.y, - reinterpret_cast(tmp.data)); + // clusters.push_back(tmp.x, tmp.y, + // reinterpret_cast(tmp.data)); + clusters.push_back(tmp); nph_read++; } } @@ -268,9 +269,10 @@ ClusterFile::read_clusters(size_t n_clusters, ROI roi) { fread(&tmp, sizeof(tmp), 1, fp); if (tmp.x >= roi.xmin && tmp.x <= roi.xmax && tmp.y >= roi.ymin && tmp.y <= roi.ymax) { - clusters.push_back( - tmp.x, tmp.y, - reinterpret_cast(tmp.data)); + // clusters.push_back( + // tmp.x, tmp.y, + // reinterpret_cast(tmp.data)); + clusters.push_back(tmp); nph_read++; } } diff --git a/include/aare/ClusterFinder.hpp b/include/aare/ClusterFinder.hpp index 9a15448..6a8fec4 100644 --- a/include/aare/ClusterFinder.hpp +++ b/include/aare/ClusterFinder.hpp @@ -140,9 +140,14 @@ class ClusterFinder { } // Add the cluster to the output ClusterVector + /* m_clusters.push_back( ix, iy, reinterpret_cast(cluster_data.data())); + */ + m_clusters.push_back( + Cluster{ + ix, iy, cluster_data.data()}); } } } diff --git a/include/aare/ClusterVector.hpp b/include/aare/ClusterVector.hpp index 0e47b51..073df13 100644 --- a/include/aare/ClusterVector.hpp +++ b/include/aare/ClusterVector.hpp @@ -100,25 +100,22 @@ class ClusterVector> { /** * @brief Add a cluster to the vector - * @param x x-coordinate of the cluster - * @param y y-coordinate of the cluster - * @param data pointer to the data of the cluster - * @warning The data pointer must point to a buffer of size cluster_size_x * - * cluster_size_y * sizeof(T) */ - void push_back(CoordType x, CoordType y, const std::byte *data) { + void push_back(const ClusterType &cluster) { if (m_size == m_capacity) { allocate_buffer(m_capacity * 2); } std::byte *ptr = element_ptr(m_size); - *reinterpret_cast(ptr) = x; + *reinterpret_cast(ptr) = cluster.x; ptr += sizeof(CoordType); - *reinterpret_cast(ptr) = y; + *reinterpret_cast(ptr) = cluster.y; ptr += sizeof(CoordType); - std::copy(data, data + ClusterSizeX * ClusterSizeY * sizeof(T), ptr); + std::memcpy(ptr, cluster.data, ClusterSizeX * ClusterSizeY * sizeof(T)); + m_size++; } + ClusterVector &operator+=(const ClusterVector &other) { if (m_size + other.m_size > m_capacity) { allocate_buffer(m_capacity + other.m_size); @@ -154,10 +151,9 @@ class ClusterVector> { * @throws std::runtime_error if the cluster size is not 3x3 * @warning Only 3x3 clusters are supported for the 2x2 sum. */ - /* only needed to calculate eta - std::vector sum_2x2() { - std::vector sums(m_size); - const size_t stride = item_size(); + /* only needed to calculate eta TODO: in previous PR already added calculate + sum in PR std::vector sum_2x2() { std::vector sums(m_size); const + size_t stride = item_size(); if (ClusterSizeX != 3 || ClusterSizeY != 3) { throw std::runtime_error( diff --git a/src/ClusterVector.test.cpp b/src/ClusterVector.test.cpp index acbbf56..b58e88a 100644 --- a/src/ClusterVector.test.cpp +++ b/src/ClusterVector.test.cpp @@ -7,7 +7,8 @@ using aare::Cluster; using aare::ClusterVector; -TEST_CASE("ClusterVector 2x2 int32_t capacity 4, push back then read") { +TEST_CASE("ClusterVector 2x2 int32_t capacity 4, push back then read", + "[.ClusterVector]") { ClusterVector> cv(4); REQUIRE(cv.capacity() == 4); @@ -19,7 +20,7 @@ TEST_CASE("ClusterVector 2x2 int32_t capacity 4, push back then read") { // Create a cluster and push back into the vector Cluster c1 = {1, 2, {3, 4, 5, 6}}; - cv.push_back(c1.x, c1.y, reinterpret_cast(&c1.data[0])); + cv.push_back(c1); REQUIRE(cv.size() == 1); REQUIRE(cv.capacity() == 4); @@ -36,7 +37,7 @@ TEST_CASE("ClusterVector 2x2 int32_t capacity 4, push back then read") { } } -TEST_CASE("Summing 3x1 clusters of int64") { +TEST_CASE("Summing 3x1 clusters of int64", "[.ClusterVector]") { ClusterVector> cv(2); REQUIRE(cv.capacity() == 2); REQUIRE(cv.size() == 0); @@ -45,17 +46,17 @@ TEST_CASE("Summing 3x1 clusters of int64") { // Create a cluster and push back into the vector Cluster c1 = {1, 2, {3, 4, 5}}; - cv.push_back(c1.x, c1.y, reinterpret_cast(&c1.data[0])); + cv.push_back(c1); REQUIRE(cv.capacity() == 2); REQUIRE(cv.size() == 1); Cluster c2 = {6, 7, {8, 9, 10}}; - cv.push_back(c2.x, c2.y, reinterpret_cast(&c2.data[0])); + cv.push_back(c2); REQUIRE(cv.capacity() == 2); REQUIRE(cv.size() == 2); Cluster c3 = {11, 12, {13, 14, 15}}; - cv.push_back(c3.x, c3.y, reinterpret_cast(&c3.data[0])); + cv.push_back(c3); REQUIRE(cv.capacity() == 4); REQUIRE(cv.size() == 3); @@ -66,7 +67,7 @@ TEST_CASE("Summing 3x1 clusters of int64") { REQUIRE(sums[2] == 42); } -TEST_CASE("Storing floats") { +TEST_CASE("Storing floats", "[.ClusterVector]") { ClusterVector> cv(10); REQUIRE(cv.capacity() == 10); REQUIRE(cv.size() == 0); @@ -75,13 +76,13 @@ TEST_CASE("Storing floats") { // Create a cluster and push back into the vector Cluster c1 = {1, 2, {3.0, 4.0, 5.0, 6.0, 3.0, 4.0, 5.0, 6.0}}; - cv.push_back(c1.x, c1.y, reinterpret_cast(&c1.data[0])); + cv.push_back(c1); REQUIRE(cv.capacity() == 10); REQUIRE(cv.size() == 1); Cluster c2 = { 6, 7, {8.0, 9.0, 10.0, 11.0, 8.0, 9.0, 10.0, 11.0}}; - cv.push_back(c2.x, c2.y, reinterpret_cast(&c2.data[0])); + cv.push_back(c2); REQUIRE(cv.capacity() == 10); REQUIRE(cv.size() == 2); @@ -91,22 +92,22 @@ TEST_CASE("Storing floats") { REQUIRE_THAT(sums[1], Catch::Matchers::WithinAbs(76.0, 1e-6)); } -TEST_CASE("Push back more than initial capacity") { +TEST_CASE("Push back more than initial capacity", "[.ClusterVector]") { ClusterVector> cv(2); auto initial_data = cv.data(); Cluster c1 = {1, 2, {3, 4, 5, 6}}; - cv.push_back(c1.x, c1.y, reinterpret_cast(&c1.data[0])); + cv.push_back(c1); REQUIRE(cv.size() == 1); REQUIRE(cv.capacity() == 2); Cluster c2 = {6, 7, {8, 9, 10, 11}}; - cv.push_back(c2.x, c2.y, reinterpret_cast(&c2.data[0])); + cv.push_back(c2); REQUIRE(cv.size() == 2); REQUIRE(cv.capacity() == 2); Cluster c3 = {11, 12, {13, 14, 15, 16}}; - cv.push_back(c3.x, c3.y, reinterpret_cast(&c3.data[0])); + cv.push_back(c3); REQUIRE(cv.size() == 3); REQUIRE(cv.capacity() == 4); @@ -124,19 +125,19 @@ TEST_CASE("Push back more than initial capacity") { REQUIRE(initial_data != cv.data()); } -TEST_CASE( - "Concatenate two cluster vectors where the first has enough capacity") { +TEST_CASE("Concatenate two cluster vectors where the first has enough capacity", + "[.ClusterVector]") { ClusterVector> cv1(12); Cluster c1 = {1, 2, {3, 4, 5, 6}}; - cv1.push_back(c1.x, c1.y, reinterpret_cast(&c1.data[0])); + cv1.push_back(c1); Cluster c2 = {6, 7, {8, 9, 10, 11}}; - cv1.push_back(c2.x, c2.y, reinterpret_cast(&c2.data[0])); + cv1.push_back(c2); ClusterVector> cv2(2); Cluster c3 = {11, 12, {13, 14, 15, 16}}; - cv2.push_back(c3.x, c3.y, reinterpret_cast(&c3.data[0])); + cv2.push_back(c3); Cluster c4 = {16, 17, {18, 19, 20, 21}}; - cv2.push_back(c4.x, c4.y, reinterpret_cast(&c4.data[0])); + cv2.push_back(c4); cv1 += cv2; REQUIRE(cv1.size() == 4); @@ -154,18 +155,19 @@ TEST_CASE( REQUIRE(ptr[3].y == 17); } -TEST_CASE("Concatenate two cluster vectors where we need to allocate") { +TEST_CASE("Concatenate two cluster vectors where we need to allocate", + "[.ClusterVector]") { ClusterVector> cv1(2); Cluster c1 = {1, 2, {3, 4, 5, 6}}; - cv1.push_back(c1.x, c1.y, reinterpret_cast(&c1.data[0])); + cv1.push_back(c1); Cluster c2 = {6, 7, {8, 9, 10, 11}}; - cv1.push_back(c2.x, c2.y, reinterpret_cast(&c2.data[0])); + cv1.push_back(c2); ClusterVector> cv2(2); Cluster c3 = {11, 12, {13, 14, 15, 16}}; - cv2.push_back(c3.x, c3.y, reinterpret_cast(&c3.data[0])); + cv2.push_back(c3); Cluster c4 = {16, 17, {18, 19, 20, 21}}; - cv2.push_back(c4.x, c4.y, reinterpret_cast(&c4.data[0])); + cv2.push_back(c4); cv1 += cv2; REQUIRE(cv1.size() == 4); diff --git a/src/Interpolator.cpp b/src/Interpolator.cpp index 1c4a385..cfe5b03 100644 --- a/src/Interpolator.cpp +++ b/src/Interpolator.cpp @@ -55,6 +55,8 @@ Interpolator::Interpolator(NDView etacube, NDView xbins, } } +// TODO: generalize to support any clustertype!!! otherwise add std::enable_if_t +// to only take Cluster2x2 and Cluster3x3 template >> std::vector From 3083d516998b91a5316efdc81d2ae9a66f11f421 Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Tue, 1 Apr 2025 17:50:11 +0200 Subject: [PATCH 14/51] merge conflict --- include/aare/CalculateEta.hpp | 6 ++++-- include/aare/ClusterVector.hpp | 22 +++++++++---------- src/ClusterFile.test.cpp | 39 +++++++++++++++------------------- 3 files changed, 32 insertions(+), 35 deletions(-) diff --git a/include/aare/CalculateEta.hpp b/include/aare/CalculateEta.hpp index 29c5cc4..57c1460 100644 --- a/include/aare/CalculateEta.hpp +++ b/include/aare/CalculateEta.hpp @@ -152,8 +152,10 @@ template Eta2 calculate_eta2(const Cluster &cl) { template Eta2 calculate_eta2(const Cluster &cl) { Eta2 eta{}; - eta.x = static_cast(cl.data[1]) / (cl.data[0] + cl.data[1]); - eta.y = static_cast(cl.data[2]) / (cl.data[0] + cl.data[2]); + if ((cl.data[0] + cl.data[1]) != 0) + eta.x = static_cast(cl.data[1]) / (cl.data[0] + cl.data[1]); + if ((cl.data[0] + cl.data[2]) != 0) + eta.y = static_cast(cl.data[2]) / (cl.data[0] + cl.data[2]); eta.sum = cl.data[0] + cl.data[1] + cl.data[2] + cl.data[3]; eta.c = cBottomLeft; // TODO! This is not correct, but need to put something return eta; diff --git a/include/aare/ClusterVector.hpp b/include/aare/ClusterVector.hpp index 4ab0aa7..188b018 100644 --- a/include/aare/ClusterVector.hpp +++ b/include/aare/ClusterVector.hpp @@ -272,25 +272,25 @@ class ClusterVector> { m_size = new_size; } - void apply_gain_map(const NDView gain_map){ - //in principle we need to know the size of the image for this lookup - //TODO! check orientations + // TODO: Generalize !!!! + void apply_gain_map(const NDView gain_map) { + // in principle we need to know the size of the image for this lookup + // TODO! check orientations std::array xcorr = {-1, 0, 1, -1, 0, 1, -1, 0, 1}; std::array ycorr = {-1, -1, -1, 0, 0, 0, 1, 1, 1}; - for (size_t i=0; i(i); + for (size_t i = 0; i < m_size; i++) { + auto &cl = at(i); - if (cl.x > 0 && cl.y > 0 && cl.x < gain_map.shape(1)-1 && cl.y < gain_map.shape(0)-1){ - for (size_t j=0; j<9; j++){ + if (cl.x > 0 && cl.y > 0 && cl.x < gain_map.shape(1) - 1 && + cl.y < gain_map.shape(0) - 1) { + for (size_t j = 0; j < 9; j++) { size_t x = cl.x + xcorr[j]; size_t y = cl.y + ycorr[j]; cl.data[j] = static_cast(cl.data[j] * gain_map(y, x)); } - }else{ - memset(cl.data, 0, 9*sizeof(T)); //clear edge clusters + } else { + memset(cl.data, 0, 9 * sizeof(T)); // clear edge clusters } - - } } diff --git a/src/ClusterFile.test.cpp b/src/ClusterFile.test.cpp index a0eed04..ccc0170 100644 --- a/src/ClusterFile.test.cpp +++ b/src/ClusterFile.test.cpp @@ -1,33 +1,32 @@ #include "aare/ClusterFile.hpp" #include "test_config.hpp" - #include "aare/defs.hpp" #include #include - - - +using aare::Cluster; using aare::ClusterFile; TEST_CASE("Read one frame from a a cluster file", "[.integration]") { - //We know that the frame has 97 clusters - auto fpath = test_data_path() / "clusters" / "single_frame_97_clustrers.clust"; + // We know that the frame has 97 clusters + auto fpath = + test_data_path() / "clusters" / "single_frame_97_clustrers.clust"; REQUIRE(std::filesystem::exists(fpath)); - ClusterFile f(fpath); + ClusterFile> f(fpath); auto clusters = f.read_frame(); REQUIRE(clusters.size() == 97); REQUIRE(clusters.frame_number() == 135); } TEST_CASE("Read one frame using ROI", "[.integration]") { - //We know that the frame has 97 clusters - auto fpath = test_data_path() / "clusters" / "single_frame_97_clustrers.clust"; + // We know that the frame has 97 clusters + auto fpath = + test_data_path() / "clusters" / "single_frame_97_clustrers.clust"; REQUIRE(std::filesystem::exists(fpath)); - ClusterFile f(fpath); + ClusterFile> f(fpath); aare::ROI roi; roi.xmin = 0; roi.xmax = 50; @@ -38,43 +37,39 @@ TEST_CASE("Read one frame using ROI", "[.integration]") { REQUIRE(clusters.size() == 49); REQUIRE(clusters.frame_number() == 135); - //Check that all clusters are within the ROI + // Check that all clusters are within the ROI for (size_t i = 0; i < clusters.size(); i++) { - auto c = clusters.at(i); + auto c = clusters.at(i); REQUIRE(c.x >= roi.xmin); REQUIRE(c.x <= roi.xmax); REQUIRE(c.y >= roi.ymin); REQUIRE(c.y <= roi.ymax); } - } - TEST_CASE("Read clusters from single frame file", "[.integration]") { - auto fpath = test_data_path() / "clusters" / "single_frame_97_clustrers.clust"; + auto fpath = + test_data_path() / "clusters" / "single_frame_97_clustrers.clust"; REQUIRE(std::filesystem::exists(fpath)); SECTION("Read fewer clusters than available") { - ClusterFile f(fpath); + ClusterFile> f(fpath); auto clusters = f.read_clusters(50); REQUIRE(clusters.size() == 50); - REQUIRE(clusters.frame_number() == 135); + REQUIRE(clusters.frame_number() == 135); } SECTION("Read more clusters than available") { - ClusterFile f(fpath); + ClusterFile> f(fpath); // 100 is the maximum number of clusters read auto clusters = f.read_clusters(100); REQUIRE(clusters.size() == 97); REQUIRE(clusters.frame_number() == 135); } SECTION("Read all clusters") { - ClusterFile f(fpath); + ClusterFile> f(fpath); auto clusters = f.read_clusters(97); REQUIRE(clusters.size() == 97); REQUIRE(clusters.frame_number() == 135); } - - - } From 04728929cba0a61831748f3179e08f9967011380 Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Tue, 1 Apr 2025 18:29:08 +0200 Subject: [PATCH 15/51] implemented sum_2x2() for general clusters, only one calculate_eta2 function for all clusters --- include/aare/CalculateEta.hpp | 80 +--- include/aare/Cluster.hpp | 22 +- include/aare/ClusterFile.hpp | 8 +- include/aare/ClusterVector.hpp | 37 +- src/Cluster.test.cpp | 3 - src/ClusterFile.cpp | 704 --------------------------------- 6 files changed, 22 insertions(+), 832 deletions(-) delete mode 100644 src/ClusterFile.cpp diff --git a/include/aare/CalculateEta.hpp b/include/aare/CalculateEta.hpp index 57c1460..1a0797a 100644 --- a/include/aare/CalculateEta.hpp +++ b/include/aare/CalculateEta.hpp @@ -60,23 +60,9 @@ Eta2 calculate_eta2( const Cluster &cl) { Eta2 eta{}; - constexpr size_t num_2x2_subclusters = - (ClusterSizeX - 1) * (ClusterSizeY - 1); - std::array sum_2x2_subcluster; - for (size_t i = 0; i < ClusterSizeY - 1; ++i) { - for (size_t j = 0; j < ClusterSizeX - 1; ++j) - sum_2x2_subcluster[i * (ClusterSizeX - 1) + j] = - cl.data[i * ClusterSizeX + j] + - cl.data[i * ClusterSizeX + j + 1] + - cl.data[(i + 1) * ClusterSizeX + j] + - cl.data[(i + 1) * ClusterSizeX + j + 1]; - } - - auto c = - std::max_element(sum_2x2_subcluster.begin(), sum_2x2_subcluster.end()) - - sum_2x2_subcluster.begin(); - - eta.sum = sum_2x2_subcluster[c]; + auto max_sum = cl.max_sum_2x2(); + eta.sum = max_sum.first; + auto c = max_sum.second; size_t index_bottom_left_max_2x2_subcluster = (int(c / (ClusterSizeX - 1))) * ClusterSizeX + c % (ClusterSizeX - 1); @@ -101,66 +87,6 @@ Eta2 calculate_eta2( return eta; } -/** - * @brief Calculate the eta2 values for a 3x3 cluster and return them in a Eta2 - * struct containing etay, etax and the corner of the cluster. - */ -template Eta2 calculate_eta2(const Cluster &cl) { - Eta2 eta{}; - - std::array tot2; - tot2[0] = cl.data[0] + cl.data[1] + cl.data[3] + cl.data[4]; - tot2[1] = cl.data[1] + cl.data[2] + cl.data[4] + cl.data[5]; - tot2[2] = cl.data[3] + cl.data[4] + cl.data[6] + cl.data[7]; - tot2[3] = cl.data[4] + cl.data[5] + cl.data[7] + cl.data[8]; - - auto c = std::max_element(tot2.begin(), tot2.end()) - tot2.begin(); - eta.sum = tot2[c]; - switch (c) { - case cBottomLeft: - if ((cl.data[3] + cl.data[4]) != 0) - eta.x = static_cast(cl.data[4]) / (cl.data[3] + cl.data[4]); - if ((cl.data[1] + cl.data[4]) != 0) - eta.y = static_cast(cl.data[4]) / (cl.data[1] + cl.data[4]); - eta.c = cBottomLeft; - break; - case cBottomRight: - if ((cl.data[2] + cl.data[5]) != 0) - eta.x = static_cast(cl.data[5]) / (cl.data[4] + cl.data[5]); - if ((cl.data[1] + cl.data[4]) != 0) - eta.y = static_cast(cl.data[4]) / (cl.data[1] + cl.data[4]); - eta.c = cBottomRight; - break; - case cTopLeft: - if ((cl.data[7] + cl.data[4]) != 0) - eta.x = static_cast(cl.data[4]) / (cl.data[3] + cl.data[4]); - if ((cl.data[7] + cl.data[4]) != 0) - eta.y = static_cast(cl.data[7]) / (cl.data[7] + cl.data[4]); - eta.c = cTopLeft; - break; - case cTopRight: - if ((cl.data[5] + cl.data[4]) != 0) - eta.x = static_cast(cl.data[5]) / (cl.data[5] + cl.data[4]); - if ((cl.data[7] + cl.data[4]) != 0) - eta.y = static_cast(cl.data[7]) / (cl.data[7] + cl.data[4]); - eta.c = cTopRight; - break; - } - return eta; -} - -template Eta2 calculate_eta2(const Cluster &cl) { - Eta2 eta{}; - - if ((cl.data[0] + cl.data[1]) != 0) - eta.x = static_cast(cl.data[1]) / (cl.data[0] + cl.data[1]); - if ((cl.data[0] + cl.data[2]) != 0) - eta.y = static_cast(cl.data[2]) / (cl.data[0] + cl.data[2]); - eta.sum = cl.data[0] + cl.data[1] + cl.data[2] + cl.data[3]; - eta.c = cBottomLeft; // TODO! This is not correct, but need to put something - return eta; -} - // calculates Eta3 for 3x3 cluster based on code from analyze_cluster // TODO only supported for 3x3 Clusters template Eta2 calculate_eta3(const Cluster &cl) { diff --git a/include/aare/Cluster.hpp b/include/aare/Cluster.hpp index da756dc..cc102c4 100644 --- a/include/aare/Cluster.hpp +++ b/include/aare/Cluster.hpp @@ -35,7 +35,7 @@ struct Cluster { return std::accumulate(data, data + ClusterSizeX * ClusterSizeY, 0); } - T max_sum_2x2() const { + std::pair max_sum_2x2() const { constexpr size_t num_2x2_subclusters = (ClusterSizeX - 1) * (ClusterSizeY - 1); @@ -49,8 +49,10 @@ struct Cluster { data[(i + 1) * ClusterSizeX + j + 1]; } - return *std::max_element(sum_2x2_subcluster.begin(), - sum_2x2_subcluster.end()); + int index = std::max_element(sum_2x2_subcluster.begin(), + sum_2x2_subcluster.end()) - + sum_2x2_subcluster.begin(); + return std::make_pair(sum_2x2_subcluster[index], index); } }; @@ -62,9 +64,9 @@ template struct Cluster { T sum() const { return std::accumulate(data, data + 4, 0); } - T max_sum_2x2() const { - return data[0] + data[1] + data[2] + - data[3]; // Only one possible 2x2 sum + std::pair max_sum_2x2() const { + return std::make_pair(data[0] + data[1] + data[2] + data[3], + 0); // Only one possible 2x2 sum } }; @@ -76,14 +78,16 @@ template struct Cluster { T sum() const { return std::accumulate(data, data + 9, 0); } - T max_sum_2x2() const { + std::pair max_sum_2x2() const { std::array sum_2x2_subclusters; sum_2x2_subclusters[0] = data[0] + data[1] + data[3] + data[4]; sum_2x2_subclusters[1] = data[1] + data[2] + data[4] + data[5]; sum_2x2_subclusters[2] = data[3] + data[4] + data[6] + data[7]; sum_2x2_subclusters[3] = data[4] + data[5] + data[7] + data[8]; - return *std::max_element(sum_2x2_subclusters.begin(), - sum_2x2_subclusters.end()); + int index = std::max_element(sum_2x2_subclusters.begin(), + sum_2x2_subclusters.end()) - + sum_2x2_subclusters.begin(); + return std::make_pair(sum_2x2_subclusters[index], index); } }; diff --git a/include/aare/ClusterFile.hpp b/include/aare/ClusterFile.hpp index 3fc855a..9c43326 100644 --- a/include/aare/ClusterFile.hpp +++ b/include/aare/ClusterFile.hpp @@ -415,10 +415,12 @@ bool ClusterFile::is_selected(ClusterType &cl) { return false; } } + // TODO types are wrong generalize if (m_noise_map) { - int32_t sum_1x1 = cl.data[4]; // central pixel - int32_t sum_2x2 = cl.max_sum_2x2(); // highest sum of 2x2 subclusters - int32_t sum_3x3 = cl.sum(); // sum of all pixels + int32_t sum_1x1 = cl.data[4]; // central pixel + int32_t sum_2x2 = + cl.max_sum_2x2().first; // highest sum of 2x2 subclusters + int32_t sum_3x3 = cl.sum(); // sum of all pixels auto noise = (*m_noise_map)(cl.y, cl.x); // TODO! check if this is correct diff --git a/include/aare/ClusterVector.hpp b/include/aare/ClusterVector.hpp index 188b018..30be5eb 100644 --- a/include/aare/ClusterVector.hpp +++ b/include/aare/ClusterVector.hpp @@ -148,38 +148,6 @@ class ClusterVector> { return sums; } - /** - * @brief Return the maximum sum of the 2x2 subclusters in each cluster - * @return std::vector vector of sums for each cluster - * @throws std::runtime_error if the cluster size is not 3x3 - * @warning Only 3x3 clusters are supported for the 2x2 sum. - */ - /* only needed to calculate eta TODO: in previous PR already added calculate - sum in PR std::vector sum_2x2() { std::vector sums(m_size); const - size_t stride = item_size(); - - if (ClusterSizeX != 3 || ClusterSizeY != 3) { - throw std::runtime_error( - "Only 3x3 clusters are supported for the 2x2 sum."); - } - std::byte *ptr = m_data + 2 * sizeof(CoordType); // skip x and y - - for (size_t i = 0; i < m_size; i++) { - std::array total; - auto T_ptr = reinterpret_cast(ptr); - total[0] = T_ptr[0] + T_ptr[1] + T_ptr[3] + T_ptr[4]; - total[1] = T_ptr[1] + T_ptr[2] + T_ptr[4] + T_ptr[5]; - total[2] = T_ptr[3] + T_ptr[4] + T_ptr[6] + T_ptr[7]; - total[3] = T_ptr[4] + T_ptr[5] + T_ptr[7] + T_ptr[8]; - - sums[i] = *std::max_element(total.begin(), total.end()); - ptr += stride; - } - - return sums; - } - */ - /** * @brief Return the number of clusters in the vector */ @@ -220,9 +188,6 @@ class ClusterVector> { return m_data + element_offset(i); } - // size_t cluster_size_x() const { return m_cluster_size_x; } - // size_t cluster_size_y() const { return m_cluster_size_y; } - std::byte *data() { return m_data; } std::byte const *data() const { return m_data; } @@ -272,7 +237,7 @@ class ClusterVector> { m_size = new_size; } - // TODO: Generalize !!!! + // TODO: Generalize !!!! Maybe move somewhere else void apply_gain_map(const NDView gain_map) { // in principle we need to know the size of the image for this lookup // TODO! check orientations diff --git a/src/Cluster.test.cpp b/src/Cluster.test.cpp index 20c3948..7918d72 100644 --- a/src/Cluster.test.cpp +++ b/src/Cluster.test.cpp @@ -33,9 +33,6 @@ using ClusterTypes = TEST_CASE("calculate_eta2", "[.cluster][.eta_calculation]") { - // weird expect cluster_start to be in bottom_left corner -> row major -> - // check how its used should be an image!! - auto [cluster, expected_eta] = GENERATE( std::make_tuple(ClusterTypes{Cluster{0, 0, {1, 2, 3, 1}}}, Eta2{2. / 3, 3. / 4, corner::cBottomLeft, 7}), diff --git a/src/ClusterFile.cpp b/src/ClusterFile.cpp deleted file mode 100644 index 221c15d..0000000 --- a/src/ClusterFile.cpp +++ /dev/null @@ -1,704 +0,0 @@ -#include "aare/ClusterFile.hpp" - -#include - -namespace aare { - -template >> -ClusterFile::ClusterFile(const std::filesystem::path &fname, - size_t chunk_size, - const std::string &mode) - : m_chunk_size(chunk_size), m_mode(mode) { - - if (mode == "r") { - fp = fopen(fname.c_str(), "rb"); - if (!fp) { - throw std::runtime_error("Could not open file for reading: " + - fname.string()); - } - } else if (mode == "w") { - fp = fopen(fname.c_str(), "wb"); - if (!fp) { - throw std::runtime_error("Could not open file for writing: " + - fname.string()); - } - } else if (mode == "a") { - fp = fopen(fname.c_str(), "ab"); - if (!fp) { - throw std::runtime_error("Could not open file for appending: " + - fname.string()); - } - } else { - throw std::runtime_error("Unsupported mode: " + mode); - } -} - -<<<<<<< HEAD -template ClusterFile::~ClusterFile() { - close(); -} -======= -void ClusterFile::set_roi(ROI roi){ - m_roi = roi; -} - -void ClusterFile::set_noise_map(const NDView noise_map){ - m_noise_map = NDArray(noise_map); -} - -void ClusterFile::set_gain_map(const NDView gain_map){ - m_gain_map = NDArray(gain_map); -} - -ClusterFile::~ClusterFile() { close(); } ->>>>>>> developer - -template void ClusterFile::close() { - if (fp) { - fclose(fp); - fp = nullptr; - } -} - -// TODO generally supported for all clsuter types -template -void ClusterFile::write_frame( - const ClusterVector &clusters) { - if (m_mode != "w" && m_mode != "a") { - throw std::runtime_error("File not opened for writing"); - } - if (!(clusters.cluster_size_x() == 3) && - !(clusters.cluster_size_y() == 3)) { - throw std::runtime_error("Only 3x3 clusters are supported"); - } - //First write the frame number - 4 bytes - int32_t frame_number = clusters.frame_number(); - if(fwrite(&frame_number, sizeof(frame_number), 1, fp)!=1){ - throw std::runtime_error(LOCATION + "Could not write frame number"); - } - - //Then write the number of clusters - 4 bytes - uint32_t n_clusters = clusters.size(); - if(fwrite(&n_clusters, sizeof(n_clusters), 1, fp)!=1){ - throw std::runtime_error(LOCATION + "Could not write number of clusters"); - } - - //Now write the clusters in the frame - if(fwrite(clusters.data(), clusters.item_size(), clusters.size(), fp)!=clusters.size()){ - throw std::runtime_error(LOCATION + "Could not write clusters"); - } -} - -<<<<<<< HEAD -template -ClusterVector -ClusterFile::read_clusters(size_t n_clusters) { -======= - -ClusterVector ClusterFile::read_clusters(size_t n_clusters){ - if (m_mode != "r") { - throw std::runtime_error("File not opened for reading"); - } - if (m_noise_map || m_roi){ - return read_clusters_with_cut(n_clusters); - }else{ - return read_clusters_without_cut(n_clusters); - } -} - -ClusterVector ClusterFile::read_clusters_without_cut(size_t n_clusters) { ->>>>>>> developer - if (m_mode != "r") { - throw std::runtime_error("File not opened for reading"); - } - - ClusterVector clusters(n_clusters); - - int32_t iframe = 0; // frame number needs to be 4 bytes! - size_t nph_read = 0; - uint32_t nn = m_num_left; - uint32_t nph = m_num_left; // number of clusters in frame needs to be 4 - - // auto buf = reinterpret_cast(clusters.data()); - auto buf = clusters.data(); - // if there are photons left from previous frame read them first - if (nph) { - if (nph > n_clusters) { - // if we have more photons left in the frame then photons to read we - // read directly the requested number - nn = n_clusters; - } else { - nn = nph; - } - nph_read += fread((buf + nph_read * clusters.item_size()), - clusters.item_size(), nn, fp); - m_num_left = nph - nn; // write back the number of photons left - } - - if (nph_read < n_clusters) { - // keep on reading frames and photons until reaching n_clusters - while (fread(&iframe, sizeof(iframe), 1, fp)) { - clusters.set_frame_number(iframe); - // read number of clusters in frame - if (fread(&nph, sizeof(nph), 1, fp)) { - if (nph > (n_clusters - nph_read)) - nn = n_clusters - nph_read; - else - nn = nph; - - nph_read += fread((buf + nph_read * clusters.item_size()), - clusters.item_size(), nn, fp); - m_num_left = nph - nn; - } - if (nph_read >= n_clusters) - break; - } - } - - // Resize the vector to the number of clusters. - // No new allocation, only change bounds. - clusters.resize(nph_read); - if(m_gain_map) - clusters.apply_gain_map(m_gain_map->view()); - return clusters; -} - -<<<<<<< HEAD -template -ClusterVector -ClusterFile::read_clusters(size_t n_clusters, ROI roi) { - if (m_mode != "r") { - throw std::runtime_error("File not opened for reading"); - } - - ClusterVector clusters; - clusters.reserve(n_clusters); - - int32_t iframe = 0; // frame number needs to be 4 bytes! - size_t nph_read = 0; - uint32_t nn = m_num_left; - uint32_t nph = m_num_left; // number of clusters in frame needs to be 4 - - // auto buf = reinterpret_cast(clusters.data()); - // auto buf = clusters.data(); - - ClusterType tmp; // this would break if the cluster size changes - - // if there are photons left from previous frame read them first - if (nph) { - if (nph > n_clusters) { - // if we have more photons left in the frame then photons to read we - // read directly the requested number - nn = n_clusters; - } else { - nn = nph; - } - // Read one cluster, in the ROI push back - // nph_read += fread((buf + nph_read*clusters.item_size()), - // clusters.item_size(), nn, fp); - for (size_t i = 0; i < nn; i++) { - fread(&tmp, sizeof(tmp), 1, fp); - if (tmp.x >= roi.xmin && tmp.x <= roi.xmax && tmp.y >= roi.ymin && - tmp.y <= roi.ymax) { - clusters.push_back(tmp.x, tmp.y, - reinterpret_cast(tmp.data)); - nph_read++; - } - } - - m_num_left = nph - nn; // write back the number of photons left - } - - if (nph_read < n_clusters) { - // keep on reading frames and photons until reaching n_clusters - while (fread(&iframe, sizeof(iframe), 1, fp)) { - // read number of clusters in frame - if (fread(&nph, sizeof(nph), 1, fp)) { - if (nph > (n_clusters - nph_read)) - nn = n_clusters - nph_read; - else - nn = nph; - - // nph_read += fread((buf + nph_read*clusters.item_size()), - // clusters.item_size(), nn, fp); - for (size_t i = 0; i < nn; i++) { - fread(&tmp, sizeof(tmp), 1, fp); - if (tmp.x >= roi.xmin && tmp.x <= roi.xmax && - tmp.y >= roi.ymin && tmp.y <= roi.ymax) { - clusters.push_back( - tmp.x, tmp.y, - reinterpret_cast(tmp.data)); - nph_read++; - } - } - m_num_left = nph - nn; - } - if (nph_read >= n_clusters) - break; - } - } - - // Resize the vector to the number of clusters. - // No new allocation, only change bounds. - clusters.resize(nph_read); - return clusters; -} - -template -ClusterVector ClusterFile::read_frame() { -======= - - -ClusterVector ClusterFile::read_clusters_with_cut(size_t n_clusters) { - ClusterVector clusters(3,3); - clusters.reserve(n_clusters); - - // if there are photons left from previous frame read them first - if (m_num_left) { - while(m_num_left && clusters.size() < n_clusters){ - Cluster3x3 c = read_one_cluster(); - if(is_selected(c)){ - clusters.push_back(c.x, c.y, reinterpret_cast(c.data)); - } - } - } - - // we did not have enough clusters left in the previous frame - // keep on reading frames until reaching n_clusters - if (clusters.size() < n_clusters) { - // sanity check - if (m_num_left) { - throw std::runtime_error(LOCATION + "Entered second loop with clusters left\n"); - } - - int32_t frame_number = 0; // frame number needs to be 4 bytes! - while (fread(&frame_number, sizeof(frame_number), 1, fp)) { - if (fread(&m_num_left, sizeof(m_num_left), 1, fp)) { - clusters.set_frame_number(frame_number); //cluster vector will hold the last frame number - while(m_num_left && clusters.size() < n_clusters){ - Cluster3x3 c = read_one_cluster(); - if(is_selected(c)){ - clusters.push_back(c.x, c.y, reinterpret_cast(c.data)); - } - } - } - - // we have enough clusters, break out of the outer while loop - if (clusters.size() >= n_clusters) - break; - } - - } - if(m_gain_map) - clusters.apply_gain_map(m_gain_map->view()); - - return clusters; -} - -Cluster3x3 ClusterFile::read_one_cluster(){ - Cluster3x3 c; - auto rc = fread(&c, sizeof(c), 1, fp); - if (rc != 1) { - throw std::runtime_error(LOCATION + "Could not read cluster"); - } - --m_num_left; - return c; -} - -ClusterVector ClusterFile::read_frame(){ - if (m_mode != "r") { - throw std::runtime_error(LOCATION + "File not opened for reading"); - } - if (m_noise_map || m_roi){ - return read_frame_with_cut(); - }else{ - return read_frame_without_cut(); - } -} - -ClusterVector ClusterFile::read_frame_without_cut() { - if (m_mode != "r") { - throw std::runtime_error("File not opened for reading"); - } - if (m_num_left) { - throw std::runtime_error( - "There are still photons left in the last frame"); - } - int32_t frame_number; - if (fread(&frame_number, sizeof(frame_number), 1, fp) != 1) { - throw std::runtime_error(LOCATION + "Could not read frame number"); - } - - int32_t n_clusters; // Saved as 32bit integer in the cluster file - if (fread(&n_clusters, sizeof(n_clusters), 1, fp) != 1) { - throw std::runtime_error(LOCATION + "Could not read number of clusters"); - } - - ClusterVector clusters(3, 3, n_clusters); - clusters.set_frame_number(frame_number); - - if (fread(clusters.data(), clusters.item_size(), n_clusters, fp) != - static_cast(n_clusters)) { - throw std::runtime_error(LOCATION + "Could not read clusters"); - } - clusters.resize(n_clusters); - if (m_gain_map) - clusters.apply_gain_map(m_gain_map->view()); - return clusters; -} - -ClusterVector ClusterFile::read_frame_with_cut() { ->>>>>>> developer - if (m_mode != "r") { - throw std::runtime_error("File not opened for reading"); - } - if (m_num_left) { - throw std::runtime_error( - "There are still photons left in the last frame"); - } - int32_t frame_number; - if (fread(&frame_number, sizeof(frame_number), 1, fp) != 1) { - throw std::runtime_error("Could not read frame number"); - } - - - if (fread(&m_num_left, sizeof(m_num_left), 1, fp) != 1) { - throw std::runtime_error("Could not read number of clusters"); - } -<<<<<<< HEAD - // std::vector clusters(n_clusters); - ClusterVector clusters(n_clusters); -======= - - ClusterVector clusters(3, 3); - clusters.reserve(m_num_left); ->>>>>>> developer - clusters.set_frame_number(frame_number); - while(m_num_left){ - Cluster3x3 c = read_one_cluster(); - if(is_selected(c)){ - clusters.push_back(c.x, c.y, reinterpret_cast(c.data)); - } - } - if (m_gain_map) - clusters.apply_gain_map(m_gain_map->view()); - return clusters; -} - -<<<<<<< HEAD -// std::vector ClusterFile::read_cluster_with_cut(size_t n_clusters, -// double *noise_map, -// int nx, int ny) { -// if (m_mode != "r") { -// throw std::runtime_error("File not opened for reading"); -// } -// std::vector clusters(n_clusters); -// // size_t read_clusters_with_cut(FILE *fp, size_t n_clusters, Cluster -// *buf, -// // uint32_t *n_left, double *noise_map, int -// // nx, int ny) { -// int iframe = 0; -// // uint32_t nph = *n_left; -// uint32_t nph = m_num_left; -// // uint32_t nn = *n_left; -// uint32_t nn = m_num_left; -// size_t nph_read = 0; -======= - ->>>>>>> developer - -bool ClusterFile::is_selected(Cluster3x3 &cl) { - //Should fail fast - if (m_roi) { - if (!(m_roi->contains(cl.x, cl.y))) { - return false; - } - } - if (m_noise_map){ - int32_t sum_1x1 = cl.data[4]; // central pixel - int32_t sum_2x2 = cl.sum_2x2(); // highest sum of 2x2 subclusters - int32_t sum_3x3 = cl.sum(); // sum of all pixels - -<<<<<<< HEAD -// if (nph) { -// if (nph > n_clusters) { -// // if we have more photons left in the frame then photons to -// // read we read directly the requested number -// nn = n_clusters; -// } else { -// nn = nph; -// } -// for (size_t iph = 0; iph < nn; iph++) { -// // read photons 1 by 1 -// size_t n_read = -// fread(reinterpret_cast(ptr), sizeof(Cluster3x3), 1, -// fp); -// if (n_read != 1) { -// clusters.resize(nph_read); -// return clusters; -// } -// // TODO! error handling on read -// good = 1; -// if (noise_map) { -// if (ptr->x >= 0 && ptr->x < nx && ptr->y >= 0 && ptr->y < ny) -// { -// tot1 = ptr->data[4]; -// analyze_cluster(*ptr, &t2max, &tot3, NULL, NULL, NULL, -// NULL, -// NULL); -// noise = noise_map[ptr->y * nx + ptr->x]; -// if (tot1 > noise || t2max > 2 * noise || tot3 > 3 * -// noise) { -// ; -// } else { -// good = 0; -// printf("%d %d %f %d %d %d\n", ptr->x, ptr->y, noise, -// tot1, t2max, tot3); -// } -// } else { -// printf("Bad pixel number %d %d\n", ptr->x, ptr->y); -// good = 0; -// } -// } -// if (good) { -// ptr++; -// nph_read++; -// } -// (m_num_left)--; -// if (nph_read >= n_clusters) -// break; -// } -// } -// if (nph_read < n_clusters) { -// // // keep on reading frames and photons until reaching -// // n_clusters -// while (fread(&iframe, sizeof(iframe), 1, fp)) { -// // // printf("%d\n",nph_read); - -// if (fread(&nph, sizeof(nph), 1, fp)) { -// // // printf("** %d\n",nph); -// m_num_left = nph; -// for (size_t iph = 0; iph < nph; iph++) { -// // // read photons 1 by 1 -// size_t n_read = fread(reinterpret_cast(ptr), -// sizeof(Cluster3x3), 1, fp); -// if (n_read != 1) { -// clusters.resize(nph_read); -// return clusters; -// // return nph_read; -// } -// good = 1; -// if (noise_map) { -// if (ptr->x >= 0 && ptr->x < nx && ptr->y >= 0 && -// ptr->y < ny) { -// tot1 = ptr->data[4]; -// analyze_cluster(*ptr, &t2max, &tot3, NULL, NULL, -// NULL, NULL, NULL); -// // noise = noise_map[ptr->y * nx + ptr->x]; -// noise = noise_map[ptr->y + ny * ptr->x]; -// if (tot1 > noise || t2max > 2 * noise || -// tot3 > 3 * noise) { -// ; -// } else -// good = 0; -// } else { -// printf("Bad pixel number %d %d\n", ptr->x, -// ptr->y); good = 0; -// } -// } -// if (good) { -// ptr++; -// nph_read++; -// } -// (m_num_left)--; -// if (nph_read >= n_clusters) -// break; -// } -// } -// if (nph_read >= n_clusters) -// break; -// } -// } -// // printf("%d\n",nph_read); -// clusters.resize(nph_read); -// return clusters; -// } -======= - auto noise = (*m_noise_map)(cl.y, cl.x); //TODO! check if this is correct - if (sum_1x1 <= noise || sum_2x2 <= 2 * noise || sum_3x3 <= 3 * noise) { - return false; - } - } - //we passed all checks - return true; -} ->>>>>>> developer - -template -NDArray calculate_eta2(ClusterVector &clusters) { - // TOTO! make work with 2x2 clusters - NDArray eta2({static_cast(clusters.size()), 2}); -<<<<<<< HEAD - - for (size_t i = 0; i < clusters.size(); i++) { - auto e = calculate_eta2(clusters.at(i)); - eta2(i, 0) = e.x; - eta2(i, 1) = e.y; - } - -======= - - if (clusters.cluster_size_x() == 3 || clusters.cluster_size_y() == 3) { - for (size_t i = 0; i < clusters.size(); i++) { - auto e = calculate_eta2(clusters.at(i)); - eta2(i, 0) = e.x; - eta2(i, 1) = e.y; - } - }else if(clusters.cluster_size_x() == 2 || clusters.cluster_size_y() == 2){ - for (size_t i = 0; i < clusters.size(); i++) { - auto e = calculate_eta2(clusters.at(i)); - eta2(i, 0) = e.x; - eta2(i, 1) = e.y; - } - }else{ - throw std::runtime_error("Only 3x3 and 2x2 clusters are supported"); - } - ->>>>>>> developer - return eta2; -} - -/** - * @brief Calculate the eta2 values for a generic sized cluster and return them - * in a Eta2 struct containing etay, etax and the index of the respective 2x2 - * subcluster. - */ -template -Eta2 calculate_eta2(Cluster &cl) { - Eta2 eta{}; - - // TODO loads of overhead for a 2x2 clsuter maybe keep 2x2 calculation - constexpr size_t num_2x2_subclusters = - (ClusterSizeX - 1) * (ClusterSizeY - 1); - std::array sum_2x2_subcluster; - for (size_t i = 0; i < ClusterSizeY - 1; ++i) { - for (size_t j = 0; j < ClusterSizeX - 1; ++j) - sum_2x2_subcluster[i * (ClusterSizeX - 1) + j] = - cl.data[i * ClusterSizeX + j] + - cl.data[i * ClusterSizeX + j + 1] + - cl.data[(i + 1) * ClusterSizeX + j] + - cl.data[(i + 1) * ClusterSizeX + j + 1]; - } - - auto c = - std::max_element(sum_2x2_subcluster.begin(), sum_2x2_subcluster.end()) - - sum_2x2_subcluster.begin(); - - eta.sum = sum_2x2_subcluster[c]; - - eta.x = static_cast(cl.data[(c + 1) * ClusterSizeX + 1]) / - (cl.data[0] + cl.data[1]); - - size_t index_top_left_2x2_subcluster = - (int(c / (ClusterSizeX - 1)) + 1) * ClusterSizeX + - c % (ClusterSizeX - 1) * 2 + 1; - if ((cl.data[index_top_left_2x2_subcluster] + - cl.data[index_top_left_2x2_subcluster - 1]) != 0) - eta.x = - static_cast(cl.data[index_top_left_2x2_subcluster] / - (cl.data[index_top_left_2x2_subcluster] + - cl.data[index_top_left_2x2_subcluster - 1])); - - if ((cl.data[index_top_left_2x2_subcluster] + - cl.data[index_top_left_2x2_subcluster - ClusterSizeX]) != 0) - eta.y = static_cast( - cl.data[index_top_left_2x2_subcluster] / - (cl.data[index_top_left_2x2_subcluster] + - cl.data[index_top_left_2x2_subcluster - ClusterSizeX])); - - eta.c = c; // TODO only supported for 2x2 and 3x3 clusters -> at least no - // underyling enum class - return eta; -} - -/** - * @brief Calculate the eta2 values for a 3x3 cluster and return them in a Eta2 - * struct containing etay, etax and the corner of the cluster. - */ -template Eta2 calculate_eta2(Cluster &cl) { - Eta2 eta{}; - - std::array tot2; - tot2[0] = cl.data[0] + cl.data[1] + cl.data[3] + cl.data[4]; - tot2[1] = cl.data[1] + cl.data[2] + cl.data[4] + cl.data[5]; - tot2[2] = cl.data[3] + cl.data[4] + cl.data[6] + cl.data[7]; - tot2[3] = cl.data[4] + cl.data[5] + cl.data[7] + cl.data[8]; - - auto c = std::max_element(tot2.begin(), tot2.end()) - tot2.begin(); - eta.sum = tot2[c]; - switch (c) { - case cBottomLeft: - if ((cl.data[3] + cl.data[4]) != 0) - eta.x = static_cast(cl.data[4]) / (cl.data[3] + cl.data[4]); - if ((cl.data[1] + cl.data[4]) != 0) - eta.y = static_cast(cl.data[4]) / (cl.data[1] + cl.data[4]); - eta.c = cBottomLeft; - break; - case cBottomRight: - if ((cl.data[2] + cl.data[5]) != 0) - eta.x = static_cast(cl.data[5]) / (cl.data[4] + cl.data[5]); - if ((cl.data[1] + cl.data[4]) != 0) - eta.y = static_cast(cl.data[4]) / (cl.data[1] + cl.data[4]); - eta.c = cBottomRight; - break; - case cTopLeft: - if ((cl.data[7] + cl.data[4]) != 0) - eta.x = static_cast(cl.data[4]) / (cl.data[3] + cl.data[4]); - if ((cl.data[7] + cl.data[4]) != 0) - eta.y = static_cast(cl.data[7]) / (cl.data[7] + cl.data[4]); - eta.c = cTopLeft; - break; - case cTopRight: - if ((cl.data[5] + cl.data[4]) != 0) - eta.x = static_cast(cl.data[5]) / (cl.data[5] + cl.data[4]); - if ((cl.data[7] + cl.data[4]) != 0) - eta.y = static_cast(cl.data[7]) / (cl.data[7] + cl.data[4]); - eta.c = cTopRight; - break; - } - return eta; -} - -<<<<<<< HEAD -template Eta2 calculate_eta2(Cluster &cl) { - Eta2 eta{}; - - eta.x = static_cast(cl.data[1]) / (cl.data[0] + cl.data[1]); - eta.y = static_cast(cl.data[2]) / (cl.data[0] + cl.data[2]); - eta.sum = cl.data[0] + cl.data[1] + cl.data[2] + cl.data[3]; - eta.c = cBottomLeft; // TODO! This is not correct, but need to put something - return eta; -} - -// TODO complicated API simplify? -int analyze_cluster(Cluster &cl, int32_t *t2, int32_t *t3, - char *quad, double *eta2x, double *eta2y, double *eta3x, - double *eta3y) { -======= ->>>>>>> developer - -Eta2 calculate_eta2(Cluster2x2 &cl) { - Eta2 eta{}; - if ((cl.data[0] + cl.data[1]) != 0) - eta.x = static_cast(cl.data[1]) / (cl.data[0] + cl.data[1]); - if ((cl.data[0] + cl.data[2]) != 0) - eta.y = static_cast(cl.data[2]) / (cl.data[0] + cl.data[2]); - eta.sum = cl.data[0] + cl.data[1] + cl.data[2]+ cl.data[3]; - eta.c = cBottomLeft; //TODO! This is not correct, but need to put something - return eta; -} - - -} // namespace aare \ No newline at end of file From 240960d3e7e5c27ad1ba82ffa8a909a92134af97 Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Wed, 2 Apr 2025 12:05:16 +0200 Subject: [PATCH 16/51] generalized FindCluster to read in general cluster sizes - assuming that finding cluster center is equal for all clusters --- include/aare/CalculateEta.hpp | 2 +- include/aare/ClusterFinder.hpp | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/include/aare/CalculateEta.hpp b/include/aare/CalculateEta.hpp index 1a0797a..088b4e8 100644 --- a/include/aare/CalculateEta.hpp +++ b/include/aare/CalculateEta.hpp @@ -67,7 +67,7 @@ Eta2 calculate_eta2( size_t index_bottom_left_max_2x2_subcluster = (int(c / (ClusterSizeX - 1))) * ClusterSizeX + c % (ClusterSizeX - 1); - if ((cl.data[index_bottom_left_max_2x2_subcluster] + + if ((cl.data[index_bottom_left_max_2x2_subcluster] +s cl.data[index_bottom_left_max_2x2_subcluster + 1]) != 0) eta.x = static_cast( cl.data[index_bottom_left_max_2x2_subcluster + 1]) / diff --git a/include/aare/ClusterFinder.hpp b/include/aare/ClusterFinder.hpp index 6a8fec4..19ada67 100644 --- a/include/aare/ClusterFinder.hpp +++ b/include/aare/ClusterFinder.hpp @@ -70,6 +70,12 @@ class ClusterFinder { // // 4,4 -> +/- 2 int dy = ClusterSizeY / 2; int dx = ClusterSizeX / 2; + int has_center_pixel_x = + ClusterSizeX % + 2; // for even sized clusters there is no proper cluster center and + // even amount of pixels around the center + int has_center_pixel_y = ClusterSizeY % 2; + m_clusters.set_frame_number(frame_number); std::vector cluster_data(ClusterSizeX * ClusterSizeY); for (int iy = 0; iy < frame.shape(0); iy++) { @@ -86,8 +92,8 @@ class ClusterFinder { continue; // NEGATIVE_PEDESTAL go to next pixel // TODO! No pedestal update??? - for (int ir = -dy; ir < dy + 1; ir++) { - for (int ic = -dx; ic < dx + 1; ic++) { + for (int ir = -dy; ir < dy + has_center_pixel_y; ir++) { + 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)) { PEDESTAL_TYPE val = @@ -125,8 +131,8 @@ 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 = -dy; ir < dy + 1; ir++) { - for (int ic = -dx; ic < dx + 1; 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 = @@ -140,11 +146,6 @@ class ClusterFinder { } // Add the cluster to the output ClusterVector - /* - m_clusters.push_back( - ix, iy, - reinterpret_cast(cluster_data.data())); - */ m_clusters.push_back( Cluster{ ix, iy, cluster_data.data()}); From 61af1105a16b818aa7998ffd2d4312352bf53bc1 Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Wed, 2 Apr 2025 14:42:38 +0200 Subject: [PATCH 17/51] templated eta and updated test --- CMakeLists.txt | 1 + include/aare/CalculateEta.hpp | 17 +++++----- src/CalculateEta.test.cpp | 62 +++++++++++++++++++++++++++++++++++ src/Cluster.test.cpp | 33 ------------------- src/Interpolator.cpp | 4 +-- 5 files changed, 73 insertions(+), 44 deletions(-) create mode 100644 src/CalculateEta.test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index df41ae8..0ab1e73 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -419,6 +419,7 @@ if(AARE_TESTS) ${CMAKE_CURRENT_SOURCE_DIR}/src/ClusterFinder.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/ClusterVector.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Cluster.test.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/CalculateEta.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/ClusterFile.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Pedestal.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/NumpyFile.test.cpp diff --git a/include/aare/CalculateEta.hpp b/include/aare/CalculateEta.hpp index 088b4e8..86871c9 100644 --- a/include/aare/CalculateEta.hpp +++ b/include/aare/CalculateEta.hpp @@ -25,12 +25,11 @@ typedef enum { pTopRight = 8 } pixel; -// TODO: maybe template this!!!!!! why int32_t???? -struct Eta2 { +template struct Eta2 { double x; double y; int c; - int32_t sum; + T sum; }; /** @@ -56,9 +55,9 @@ NDArray calculate_eta2(const ClusterVector &clusters) { */ template -Eta2 calculate_eta2( - const Cluster &cl) { - Eta2 eta{}; +Eta2 +calculate_eta2(const Cluster &cl) { + Eta2 eta{}; auto max_sum = cl.max_sum_2x2(); eta.sum = max_sum.first; @@ -67,7 +66,7 @@ Eta2 calculate_eta2( size_t index_bottom_left_max_2x2_subcluster = (int(c / (ClusterSizeX - 1))) * ClusterSizeX + c % (ClusterSizeX - 1); - if ((cl.data[index_bottom_left_max_2x2_subcluster] +s + if ((cl.data[index_bottom_left_max_2x2_subcluster] + cl.data[index_bottom_left_max_2x2_subcluster + 1]) != 0) eta.x = static_cast( cl.data[index_bottom_left_max_2x2_subcluster + 1]) / @@ -89,9 +88,9 @@ Eta2 calculate_eta2( // calculates Eta3 for 3x3 cluster based on code from analyze_cluster // TODO only supported for 3x3 Clusters -template Eta2 calculate_eta3(const Cluster &cl) { +template Eta2 calculate_eta3(const Cluster &cl) { - Eta2 eta{}; + Eta2 eta{}; T sum = 0; diff --git a/src/CalculateEta.test.cpp b/src/CalculateEta.test.cpp new file mode 100644 index 0000000..2bdf387 --- /dev/null +++ b/src/CalculateEta.test.cpp @@ -0,0 +1,62 @@ +/************************************************ + * @file CalculateEta.test.cpp + * @short test case to calculate_eta2 + ***********************************************/ + +#include "aare/CalculateEta.hpp" +#include "aare/Cluster.hpp" +#include "aare/ClusterFile.hpp" + +// #include "catch.hpp" +#include +#include +#include + +using namespace aare; + +using ClusterTypes = + std::variant, Cluster, Cluster, + Cluster, Cluster>; + +auto get_test_parameters() { + return GENERATE( + std::make_tuple(ClusterTypes{Cluster{0, 0, {1, 2, 3, 1}}}, + Eta2{2. / 3, 3. / 4, corner::cBottomLeft, 7}), + std::make_tuple( + ClusterTypes{Cluster{0, 0, {1, 2, 3, 4, 5, 6, 1, 2, 7}}}, + Eta2{6. / 11, 2. / 7, corner::cTopRight, 20}), + std::make_tuple(ClusterTypes{Cluster{ + 0, 0, {1, 6, 7, 6, 5, 4, 3, 2, 1, 8, 8, 9, 2, + 1, 4, 5, 6, 7, 8, 4, 1, 1, 1, 1, 1}}}, + Eta2{9. / 17, 5. / 13, 8, 28}), + std::make_tuple( + ClusterTypes{Cluster{0, 0, {1, 4, 7, 2, 5, 6, 4, 3}}}, + Eta2{7. / 11, 6. / 10, 1, 21}), + std::make_tuple( + ClusterTypes{Cluster{0, 0, {1, 3, 2, 3, 4, 2}}}, + Eta2{3. / 5, 4. / 6, 1, 11})); +} + +TEST_CASE("compute_largest_2x2_subcluster", "[.eta_calculation]") { + auto [cluster, expected_eta] = get_test_parameters(); + + auto [sum, index] = std::visit( + [](const auto &clustertype) { return clustertype.max_sum_2x2(); }, + cluster); + CHECK(expected_eta.c == index); + CHECK(expected_eta.sum == sum); +} + +TEST_CASE("calculate_eta2", "[.eta_calculation]") { + + auto [cluster, expected_eta] = get_test_parameters(); + + auto eta = std::visit( + [](const auto &clustertype) { return calculate_eta2(clustertype); }, + cluster); + + CHECK(eta.x == expected_eta.x); + CHECK(eta.y == expected_eta.y); + CHECK(eta.c == expected_eta.c); + CHECK(eta.sum == expected_eta.sum); +} diff --git a/src/Cluster.test.cpp b/src/Cluster.test.cpp index 7918d72..e502012 100644 --- a/src/Cluster.test.cpp +++ b/src/Cluster.test.cpp @@ -26,36 +26,3 @@ TEST_CASE("Correct Instantiation of Cluster and ClusterVector", CHECK(not is_cluster_v); CHECK(is_cluster_v>); } - -using ClusterTypes = - std::variant, Cluster, Cluster, - Cluster, Cluster>; - -TEST_CASE("calculate_eta2", "[.cluster][.eta_calculation]") { - - auto [cluster, expected_eta] = GENERATE( - std::make_tuple(ClusterTypes{Cluster{0, 0, {1, 2, 3, 1}}}, - Eta2{2. / 3, 3. / 4, corner::cBottomLeft, 7}), - std::make_tuple( - ClusterTypes{Cluster{0, 0, {1, 2, 3, 4, 5, 6, 1, 2, 7}}}, - Eta2{6. / 11, 2. / 7, corner::cTopRight, 20}), - std::make_tuple(ClusterTypes{Cluster{ - 0, 0, {1, 6, 7, 6, 5, 4, 3, 2, 1, 8, 8, 9, 2, - 1, 4, 5, 6, 7, 8, 4, 1, 1, 1, 1, 1}}}, - Eta2{9. / 17, 5. / 13, 8, 28}), - std::make_tuple( - ClusterTypes{Cluster{0, 0, {1, 4, 7, 2, 5, 6, 4, 3}}}, - Eta2{7. / 11, 6. / 10, 1, 21}), - std::make_tuple( - ClusterTypes{Cluster{0, 0, {1, 3, 2, 3, 4, 2}}}, - Eta2{3. / 5, 4. / 6, 1, 11})); - - Eta2 eta = std::visit( - [](const auto &clustertype) { return calculate_eta2(clustertype); }, - cluster); - - CHECK(eta.x == expected_eta.x); - CHECK(eta.y == expected_eta.y); - CHECK(eta.c == expected_eta.c); - CHECK(eta.sum == expected_eta.sum); -} diff --git a/src/Interpolator.cpp b/src/Interpolator.cpp index e434231..e4f8e5c 100644 --- a/src/Interpolator.cpp +++ b/src/Interpolator.cpp @@ -68,7 +68,7 @@ Interpolator::interpolate(const ClusterVector &clusters) { for (size_t i = 0; i < clusters.size(); i++) { auto cluster = clusters.at(i); - Eta2 eta = calculate_eta2(cluster); + auto eta = calculate_eta2(cluster); Photon photon; photon.x = cluster.x; @@ -118,7 +118,7 @@ Interpolator::interpolate(const ClusterVector &clusters) { clusters.cluster_size_y() == 2) { for (size_t i = 0; i < clusters.size(); i++) { auto cluster = clusters.at(i); - Eta2 eta = calculate_eta2(cluster); + auto eta = calculate_eta2(cluster); Photon photon; photon.x = cluster.x; From 98d2d6098e64e767efdb1c3297b649100354f5c9 Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Wed, 2 Apr 2025 16:00:46 +0200 Subject: [PATCH 18/51] refactored other cpp files --- include/aare/ClusterCollector.hpp | 56 +++++++++++++++-------------- include/aare/ClusterFileSink.hpp | 58 +++++++++++++++++-------------- 2 files changed, 61 insertions(+), 53 deletions(-) diff --git a/include/aare/ClusterCollector.hpp b/include/aare/ClusterCollector.hpp index 0738062..0a53cd0 100644 --- a/include/aare/ClusterCollector.hpp +++ b/include/aare/ClusterCollector.hpp @@ -2,29 +2,31 @@ #include #include -#include "aare/ProducerConsumerQueue.hpp" -#include "aare/ClusterVector.hpp" #include "aare/ClusterFinderMT.hpp" +#include "aare/ClusterVector.hpp" +#include "aare/ProducerConsumerQueue.hpp" namespace aare { -class ClusterCollector{ - ProducerConsumerQueue>* m_source; - std::atomic m_stop_requested{false}; - std::atomic m_stopped{true}; - std::chrono::milliseconds m_default_wait{1}; - std::thread m_thread; - std::vector> m_clusters; +template >> +class ClusterCollector { + ProducerConsumerQueue> *m_source; + std::atomic m_stop_requested{false}; + std::atomic m_stopped{true}; + std::chrono::milliseconds m_default_wait{1}; + std::thread m_thread; + std::vector> m_clusters; - void process(){ + void process() { m_stopped = false; fmt::print("ClusterCollector started\n"); - while (!m_stop_requested || !m_source->isEmpty()) { - if (ClusterVector *clusters = m_source->frontPtr(); + while (!m_stop_requested || !m_source->isEmpty()) { + if (ClusterVector *clusters = m_source->frontPtr(); clusters != nullptr) { m_clusters.push_back(std::move(*clusters)); m_source->popFront(); - }else{ + } else { std::this_thread::sleep_for(m_default_wait); } } @@ -32,21 +34,21 @@ class ClusterCollector{ m_stopped = true; } - public: - ClusterCollector(ClusterFinderMT* source){ - m_source = source->sink(); - m_thread = std::thread(&ClusterCollector::process, this); - } - void stop(){ - m_stop_requested = true; - m_thread.join(); - } - std::vector> steal_clusters(){ - if(!m_stopped){ - throw std::runtime_error("ClusterCollector is still running"); - } - return std::move(m_clusters); + public: + ClusterCollector(ClusterFinderMT *source) { + m_source = source->sink(); + m_thread = std::thread(&ClusterCollector::process, this); + } + void stop() { + m_stop_requested = true; + m_thread.join(); + } + std::vector> steal_clusters() { + if (!m_stopped) { + throw std::runtime_error("ClusterCollector is still running"); } + return std::move(m_clusters); + } }; } // namespace aare \ No newline at end of file diff --git a/include/aare/ClusterFileSink.hpp b/include/aare/ClusterFileSink.hpp index 158fdeb..520fbe3 100644 --- a/include/aare/ClusterFileSink.hpp +++ b/include/aare/ClusterFileSink.hpp @@ -3,35 +3,41 @@ #include #include -#include "aare/ProducerConsumerQueue.hpp" -#include "aare/ClusterVector.hpp" #include "aare/ClusterFinderMT.hpp" +#include "aare/ClusterVector.hpp" +#include "aare/ProducerConsumerQueue.hpp" -namespace aare{ +namespace aare { -class ClusterFileSink{ - ProducerConsumerQueue>* m_source; +template class ClusterFileSink { + ProducerConsumerQueue> *m_source; std::atomic m_stop_requested{false}; std::atomic m_stopped{true}; std::chrono::milliseconds m_default_wait{1}; std::thread m_thread; std::ofstream m_file; - - void process(){ + void process() { m_stopped = false; fmt::print("ClusterFileSink started\n"); - while (!m_stop_requested || !m_source->isEmpty()) { - if (ClusterVector *clusters = m_source->frontPtr(); + while (!m_stop_requested || !m_source->isEmpty()) { + if (ClusterVector *clusters = m_source->frontPtr(); clusters != nullptr) { // Write clusters to file - int32_t frame_number = clusters->frame_number(); //TODO! Should we store frame number already as int? + int32_t frame_number = + clusters->frame_number(); // TODO! Should we store frame + // number already as int? uint32_t num_clusters = clusters->size(); - m_file.write(reinterpret_cast(&frame_number), sizeof(frame_number)); - m_file.write(reinterpret_cast(&num_clusters), sizeof(num_clusters)); - m_file.write(reinterpret_cast(clusters->data()), clusters->size() * clusters->item_size()); + m_file.write(reinterpret_cast(&frame_number), + sizeof(frame_number)); + m_file.write(reinterpret_cast(&num_clusters), + sizeof(num_clusters)); + m_file.write(reinterpret_cast(clusters->data()), + clusters->size() * clusters->item_size()); m_source->popFront(); - }else{ + } else { std::this_thread::sleep_for(m_default_wait); } } @@ -39,18 +45,18 @@ class ClusterFileSink{ m_stopped = true; } - public: - ClusterFileSink(ClusterFinderMT* source, const std::filesystem::path& fname){ - m_source = source->sink(); - m_thread = std::thread(&ClusterFileSink::process, this); - m_file.open(fname, std::ios::binary); - } - void stop(){ - m_stop_requested = true; - m_thread.join(); - m_file.close(); - } + public: + ClusterFileSink(ClusterFinderMT *source, + const std::filesystem::path &fname) { + m_source = source->sink(); + m_thread = std::thread(&ClusterFileSink::process, this); + m_file.open(fname, std::ios::binary); + } + void stop() { + m_stop_requested = true; + m_thread.join(); + m_file.close(); + } }; - } // namespace aare \ No newline at end of file From 50eeba40059b37a22d8e2cec4138a379f9c98eaa Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Wed, 2 Apr 2025 17:58:26 +0200 Subject: [PATCH 19/51] restructured GainMap to have own class and generalized --- CMakeLists.txt | 1 + include/aare/ClusterFile.hpp | 30 ++++++++++++----- include/aare/ClusterVector.hpp | 24 +------------- include/aare/GainMap.hpp | 59 ++++++++++++++++++++++++++++++++++ src/ClusterVector.test.cpp | 46 ++++++++++++++++++++++++++ 5 files changed, 129 insertions(+), 31 deletions(-) create mode 100644 include/aare/GainMap.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ab1e73..b02303c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -344,6 +344,7 @@ set(PUBLICHEADERS include/aare/Fit.hpp include/aare/FileInterface.hpp include/aare/Frame.hpp + include/aare/GainMap.hpp include/aare/geo_helpers.hpp include/aare/NDArray.hpp include/aare/NDView.hpp diff --git a/include/aare/ClusterFile.hpp b/include/aare/ClusterFile.hpp index 9c43326..eb6cc86 100644 --- a/include/aare/ClusterFile.hpp +++ b/include/aare/ClusterFile.hpp @@ -2,6 +2,7 @@ #include "aare/Cluster.hpp" #include "aare/ClusterVector.hpp" +#include "aare/GainMap.hpp" #include "aare/NDArray.hpp" #include "aare/defs.hpp" #include @@ -44,9 +45,8 @@ class ClusterFile { std::optional m_roi; /*Region of interest, will be applied if set*/ std::optional> m_noise_map; /*Noise map to cut photons, will be applied if set*/ - std::optional> - m_gain_map; /*Gain map to apply to the clusters, will be applied if - set*/ + std::optional m_gain_map; /*Gain map to apply to the clusters, will + be applied if set*/ public: /** @@ -107,6 +107,10 @@ class ClusterFile { */ void set_gain_map(const NDView gain_map); + void set_gain_map(const GainMap &gain_map); + + void set_gain_map(const GainMap &&gain_map); + /** * @brief Close the file. If not closed the file will be closed in the * destructor @@ -175,7 +179,17 @@ void ClusterFile::set_noise_map( template void ClusterFile::set_gain_map( const NDView gain_map) { - m_gain_map = NDArray(gain_map); + m_gain_map = GainMap(gain_map); +} + +template +void ClusterFile::set_gain_map(const GainMap &gain_map) { + m_gain_map = gain_map; +} + +template +void ClusterFile::set_gain_map(const GainMap &&gain_map) { + m_gain_map = gain_map; } // TODO generally supported for all clsuter types @@ -263,7 +277,7 @@ ClusterFile::read_clusters_without_cut(size_t n_clusters) { // No new allocation, only change bounds. clusters.resize(nph_read); if (m_gain_map) - clusters.apply_gain_map(m_gain_map->view()); + m_gain_map->apply_gain_map(clusters); return clusters; } @@ -312,7 +326,7 @@ ClusterFile::read_clusters_with_cut(size_t n_clusters) { } } if (m_gain_map) - clusters.apply_gain_map(m_gain_map->view()); + m_gain_map->apply_gain_map(clusters); return clusters; } @@ -370,7 +384,7 @@ ClusterFile::read_frame_without_cut() { } clusters.resize(n_clusters); if (m_gain_map) - clusters.apply_gain_map(m_gain_map->view()); + m_gain_map->apply_gain_map(clusters); return clusters; } @@ -403,7 +417,7 @@ ClusterFile::read_frame_with_cut() { } } if (m_gain_map) - clusters.apply_gain_map(m_gain_map->view()); + m_gain_map->apply_gain_map(clusters); return clusters; } diff --git a/include/aare/ClusterVector.hpp b/include/aare/ClusterVector.hpp index 30be5eb..ca2fd4d 100644 --- a/include/aare/ClusterVector.hpp +++ b/include/aare/ClusterVector.hpp @@ -32,7 +32,6 @@ class ClusterVector; // Forward declaration template class ClusterVector> { - using value_type = T; std::byte *m_data{}; size_t m_size{0}; @@ -49,6 +48,7 @@ class ClusterVector> { constexpr static char m_fmt_base[] = "=h:x:\nh:y:\n({},{}){}:data:"; public: + using value_type = T; using ClusterType = Cluster; /** @@ -237,28 +237,6 @@ class ClusterVector> { m_size = new_size; } - // TODO: Generalize !!!! Maybe move somewhere else - void apply_gain_map(const NDView gain_map) { - // in principle we need to know the size of the image for this lookup - // TODO! check orientations - std::array xcorr = {-1, 0, 1, -1, 0, 1, -1, 0, 1}; - std::array ycorr = {-1, -1, -1, 0, 0, 0, 1, 1, 1}; - for (size_t i = 0; i < m_size; i++) { - auto &cl = at(i); - - if (cl.x > 0 && cl.y > 0 && cl.x < gain_map.shape(1) - 1 && - cl.y < gain_map.shape(0) - 1) { - for (size_t j = 0; j < 9; j++) { - size_t x = cl.x + xcorr[j]; - size_t y = cl.y + ycorr[j]; - cl.data[j] = static_cast(cl.data[j] * gain_map(y, x)); - } - } else { - memset(cl.data, 0, 9 * sizeof(T)); // clear edge clusters - } - } - } - private: void allocate_buffer(size_t new_capacity) { size_t num_bytes = item_size() * new_capacity; diff --git a/include/aare/GainMap.hpp b/include/aare/GainMap.hpp new file mode 100644 index 0000000..9eb7c11 --- /dev/null +++ b/include/aare/GainMap.hpp @@ -0,0 +1,59 @@ +/************************************************ + * @file ApplyGainMap.hpp + * @short function to apply gain map of image size to a vector of clusters + ***********************************************/ + +#pragma once +#include "aare/Cluster.hpp" +#include "aare/ClusterVector.hpp" +#include "aare/NDArray.hpp" +#include "aare/NDView.hpp" +#include + +namespace aare { + +class GainMap { + + public: + explicit GainMap(const NDArray &gain_map) + : m_gain_map(gain_map) {}; + + explicit GainMap(const NDView gain_map) { + m_gain_map = NDArray(gain_map); + } + + template >> + void apply_gain_map(ClusterVector &clustervec) { + // in principle we need to know the size of the image for this lookup + // TODO! check orientations + size_t ClusterSizeX = clustervec.cluster_size_x(); + size_t ClusterSizeY = clustervec.cluster_size_y(); + + using T = typename ClusterVector::value_type; + + int64_t index_cluster_center_x = ClusterSizeX / 2; + int64_t index_cluster_center_y = ClusterSizeY / 2; + for (size_t i = 0; i < clustervec.size(); i++) { + auto &cl = clustervec.at(i); + + if (cl.x > 0 && cl.y > 0 && cl.x < m_gain_map.shape(1) - 1 && + cl.y < m_gain_map.shape(0) - 1) { + for (size_t j = 0; j < ClusterSizeX * ClusterSizeY; j++) { + size_t x = cl.x + j % ClusterSizeX - index_cluster_center_x; + size_t y = cl.y + j / ClusterSizeX - index_cluster_center_y; + cl.data[j] = static_cast(cl.data[j] * m_gain_map(y, x)); + } + } else { + memset(cl.data, 0, + ClusterSizeX * ClusterSizeY * + sizeof(T)); // clear edge clusters + } + } + } + + private: + NDArray m_gain_map{}; +}; + +} // end of namespace aare \ No newline at end of file diff --git a/src/ClusterVector.test.cpp b/src/ClusterVector.test.cpp index b58e88a..c354891 100644 --- a/src/ClusterVector.test.cpp +++ b/src/ClusterVector.test.cpp @@ -1,6 +1,7 @@ #include "aare/ClusterVector.hpp" #include +#include #include #include @@ -183,4 +184,49 @@ TEST_CASE("Concatenate two cluster vectors where we need to allocate", REQUIRE(ptr[2].y == 12); REQUIRE(ptr[3].x == 16); REQUIRE(ptr[3].y == 17); +} + +struct ClusterTestData { + int8_t ClusterSizeX; + int8_t ClusterSizeY; + std::vector index_map_x; + std::vector index_map_y; +}; + +TEST_CASE("Gain Map Calculation Index Map", "[.ClusterVector][.gain_map]") { + + auto clustertestdata = GENERATE( + ClusterTestData{3, + 3, + {-1, 0, 1, -1, 0, 1, -1, 0, 1}, + {-1, -1, -1, 0, 0, 0, 1, 1, 1}}, + ClusterTestData{ + 4, + 4, + {-2, -1, 0, 1, -2, -1, 0, 1, -2, -1, 0, 1, -2, -1, 0, 1}, + {-2, -2, -2, -2, -1, -1, -1, -1, 0, 0, 0, 0, 1, 1, 1, 1}}, + ClusterTestData{2, 2, {-1, 0, -1, 0}, {-1, -1, 0, 0}}, + ClusterTestData{5, + 5, + {-2, -1, 0, 1, 2, -2, -1, 0, 1, 2, -2, -1, 0, + 1, 2, -2, -1, 0, 1, 2, -2, -1, 0, 1, 2}, + {-2, -2, -2, -2, -2, -1, -1, -1, -1, -1, 0, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2}}); + + int8_t ClusterSizeX = clustertestdata.ClusterSizeX; + int8_t ClusterSizeY = clustertestdata.ClusterSizeY; + + std::vector index_map_x(ClusterSizeX * ClusterSizeY); + std::vector index_map_y(ClusterSizeX * ClusterSizeY); + + int64_t index_cluster_center_x = ClusterSizeX / 2; + int64_t index_cluster_center_y = ClusterSizeY / 2; + + for (size_t j = 0; j < ClusterSizeX * ClusterSizeY; j++) { + index_map_x[j] = j % ClusterSizeX - index_cluster_center_x; + index_map_y[j] = j / ClusterSizeX - index_cluster_center_y; + } + + CHECK(index_map_x == clustertestdata.index_map_x); + CHECK(index_map_y == clustertestdata.index_map_y); } \ No newline at end of file From 85a6b5b95eabd6724567e4920b7d3e208056ed1d Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Thu, 3 Apr 2025 09:28:02 +0200 Subject: [PATCH 20/51] suppress compiler warnings --- benchmarks/calculateeta_benchmark.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/benchmarks/calculateeta_benchmark.cpp b/benchmarks/calculateeta_benchmark.cpp index 609ce89..a320188 100644 --- a/benchmarks/calculateeta_benchmark.cpp +++ b/benchmarks/calculateeta_benchmark.cpp @@ -9,7 +9,10 @@ class ClusterFixture : public benchmark::Fixture { Cluster cluster_2x2{}; Cluster cluster_3x3{}; - void SetUp(::benchmark::State &state) { + private: + using benchmark::Fixture::SetUp; + + void SetUp([[maybe_unused]] const benchmark::State &state) override { int temp_data[4] = {1, 2, 3, 1}; std::copy(std::begin(temp_data), std::end(temp_data), std::begin(cluster_2x2.data)); From de9fc16e896c439695e4b461104a4c7f057e282f Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Thu, 3 Apr 2025 09:28:54 +0200 Subject: [PATCH 21/51] generalize is_selected --- include/aare/Cluster.hpp | 16 ++++++++++++++++ include/aare/ClusterFile.hpp | 20 ++++++++++++++------ src/ClusterVector.test.cpp | 8 ++++---- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/include/aare/Cluster.hpp b/include/aare/Cluster.hpp index cc102c4..46be10d 100644 --- a/include/aare/Cluster.hpp +++ b/include/aare/Cluster.hpp @@ -100,4 +100,20 @@ struct is_cluster> : std::true_type {}; // Cluster template constexpr bool is_cluster_v = is_cluster::value; +template >> +struct extract_template_arguments; // Forward declaration + +// helper struct to extract template argument +template +struct extract_template_arguments< + Cluster> { + + using type = T; + static constexpr int cluster_size_x = ClusterSizeX; + static constexpr int cluster_size_y = ClusterSizeY; + using coordtype = CoordType; +}; + } // namespace aare diff --git a/include/aare/ClusterFile.hpp b/include/aare/ClusterFile.hpp index eb6cc86..bc0ebd1 100644 --- a/include/aare/ClusterFile.hpp +++ b/include/aare/ClusterFile.hpp @@ -429,16 +429,24 @@ bool ClusterFile::is_selected(ClusterType &cl) { return false; } } - // TODO types are wrong generalize + + auto cluster_size_x = extract_template_arguments< + std::remove_reference_t>::cluster_size_x; + auto cluster_size_y = extract_template_arguments< + std::remove_reference_t>::cluster_size_y; + + size_t cluster_center_index = + (cluster_size_x / 2) + (cluster_size_y / 2) * cluster_size_x; + if (m_noise_map) { - int32_t sum_1x1 = cl.data[4]; // central pixel - int32_t sum_2x2 = - cl.max_sum_2x2().first; // highest sum of 2x2 subclusters - int32_t sum_3x3 = cl.sum(); // sum of all pixels + auto sum_1x1 = cl.data[cluster_center_index]; // central pixel + auto sum_2x2 = cl.max_sum_2x2().first; // highest sum of 2x2 subclusters + auto total_sum = cl.sum(); // sum of all pixels auto noise = (*m_noise_map)(cl.y, cl.x); // TODO! check if this is correct - if (sum_1x1 <= noise || sum_2x2 <= 2 * noise || sum_3x3 <= 3 * noise) { + if (sum_1x1 <= noise || sum_2x2 <= 2 * noise || + total_sum <= 3 * noise) { return false; } } diff --git a/src/ClusterVector.test.cpp b/src/ClusterVector.test.cpp index c354891..c6a36d8 100644 --- a/src/ClusterVector.test.cpp +++ b/src/ClusterVector.test.cpp @@ -187,8 +187,8 @@ TEST_CASE("Concatenate two cluster vectors where we need to allocate", } struct ClusterTestData { - int8_t ClusterSizeX; - int8_t ClusterSizeY; + uint8_t ClusterSizeX; + uint8_t ClusterSizeY; std::vector index_map_x; std::vector index_map_y; }; @@ -213,8 +213,8 @@ TEST_CASE("Gain Map Calculation Index Map", "[.ClusterVector][.gain_map]") { {-2, -2, -2, -2, -2, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2}}); - int8_t ClusterSizeX = clustertestdata.ClusterSizeX; - int8_t ClusterSizeY = clustertestdata.ClusterSizeY; + uint8_t ClusterSizeX = clustertestdata.ClusterSizeX; + uint8_t ClusterSizeY = clustertestdata.ClusterSizeY; std::vector index_map_x(ClusterSizeX * ClusterSizeY); std::vector index_map_y(ClusterSizeX * ClusterSizeY); From d7ef9bb1d8e933a6059bef9236a45f2150cc28d4 Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Thu, 3 Apr 2025 11:36:15 +0200 Subject: [PATCH 22/51] missed some refactoring of datatypes --- include/aare/Cluster.hpp | 6 +++--- include/aare/ClusterCollector.hpp | 2 +- include/aare/ClusterFileSink.hpp | 6 +++--- include/aare/ClusterFinder.hpp | 27 ++++++++++++++------------- include/aare/ClusterFinderMT.hpp | 22 ++++++++++++++-------- include/aare/ClusterVector.hpp | 14 ++++++++++++++ include/aare/GainMap.hpp | 1 - 7 files changed, 49 insertions(+), 29 deletions(-) diff --git a/include/aare/Cluster.hpp b/include/aare/Cluster.hpp index 46be10d..ca2e01f 100644 --- a/include/aare/Cluster.hpp +++ b/include/aare/Cluster.hpp @@ -100,8 +100,8 @@ struct is_cluster> : std::true_type {}; // Cluster template constexpr bool is_cluster_v = is_cluster::value; -template >> +template +// typename = std::enable_if_t>> struct extract_template_arguments; // Forward declaration // helper struct to extract template argument @@ -110,7 +110,7 @@ template > { - using type = T; + using value_type = T; static constexpr int cluster_size_x = ClusterSizeX; static constexpr int cluster_size_y = ClusterSizeY; using coordtype = CoordType; diff --git a/include/aare/ClusterCollector.hpp b/include/aare/ClusterCollector.hpp index 0a53cd0..cb49f58 100644 --- a/include/aare/ClusterCollector.hpp +++ b/include/aare/ClusterCollector.hpp @@ -35,7 +35,7 @@ class ClusterCollector { } public: - ClusterCollector(ClusterFinderMT *source) { + ClusterCollector(ClusterFinderMT *source) { m_source = source->sink(); m_thread = std::thread(&ClusterCollector::process, this); } diff --git a/include/aare/ClusterFileSink.hpp b/include/aare/ClusterFileSink.hpp index 520fbe3..810e63c 100644 --- a/include/aare/ClusterFileSink.hpp +++ b/include/aare/ClusterFileSink.hpp @@ -10,8 +10,8 @@ namespace aare { template class ClusterFileSink { + typename = std::enable_if_t>> +class ClusterFileSink { ProducerConsumerQueue> *m_source; std::atomic m_stop_requested{false}; std::atomic m_stopped{true}; @@ -46,7 +46,7 @@ template *source, + ClusterFileSink(ClusterFinderMT *source, const std::filesystem::path &fname) { m_source = source->sink(); m_thread = std::thread(&ClusterFileSink::process, this); diff --git a/include/aare/ClusterFinder.hpp b/include/aare/ClusterFinder.hpp index 19ada67..120d39d 100644 --- a/include/aare/ClusterFinder.hpp +++ b/include/aare/ClusterFinder.hpp @@ -10,16 +10,21 @@ namespace aare { -template +template , + typename FRAME_TYPE = uint16_t, typename PEDESTAL_TYPE = double> class ClusterFinder { Shape<2> m_image_size; const PEDESTAL_TYPE m_nSigma; const PEDESTAL_TYPE c2; const PEDESTAL_TYPE c3; Pedestal m_pedestal; - ClusterVector> m_clusters; + ClusterVector m_clusters; + + static const uint8_t ClusterSizeX = + extract_template_arguments::cluster_size_x; + static const uint8_t ClusterSizeY = + extract_template_arguments::cluster_size_x; + using CT = typename extract_template_arguments::value_type; public: /** @@ -52,16 +57,13 @@ class ClusterFinder { * same capacity as the old one * */ - ClusterVector> + ClusterVector steal_clusters(bool realloc_same_capacity = false) { - ClusterVector> tmp = - std::move(m_clusters); + ClusterVector tmp = std::move(m_clusters); if (realloc_same_capacity) - m_clusters = ClusterVector>( - tmp.capacity()); + m_clusters = ClusterVector(tmp.capacity()); else - m_clusters = - ClusterVector>{}; + m_clusters = ClusterVector{}; return tmp; } void find_clusters(NDView frame, uint64_t frame_number = 0) { @@ -147,8 +149,7 @@ class ClusterFinder { // Add the cluster to the output ClusterVector m_clusters.push_back( - Cluster{ - ix, iy, cluster_data.data()}); + ClusterType{ix, iy, cluster_data.data()}); } } } diff --git a/include/aare/ClusterFinderMT.hpp b/include/aare/ClusterFinderMT.hpp index 1efb843..62046b7 100644 --- a/include/aare/ClusterFinderMT.hpp +++ b/include/aare/ClusterFinderMT.hpp @@ -30,14 +30,16 @@ struct FrameWrapper { * @tparam PEDESTAL_TYPE type of the pedestal data * @tparam CT type of the cluster data */ -template +template , + typename FRAME_TYPE = uint16_t, typename PEDESTAL_TYPE = double> class ClusterFinderMT { + + using CT = typename extract_template_arguments::value_type; size_t m_current_thread{0}; size_t m_n_threads{0}; - using Finder = ClusterFinder; + using Finder = ClusterFinder; using InputQueue = ProducerConsumerQueue; - using OutputQueue = ProducerConsumerQueue>; + using OutputQueue = ProducerConsumerQueue>; std::vector> m_input_queues; std::vector> m_output_queues; @@ -66,7 +68,8 @@ class ClusterFinderMT { switch (frame->type) { case FrameType::DATA: cf->find_clusters(frame->data.view(), frame->frame_number); - m_output_queues[thread_id]->write(cf->steal_clusters(realloc_same_capacity)); + m_output_queues[thread_id]->write( + cf->steal_clusters(realloc_same_capacity)); break; case FrameType::PEDESTAL: @@ -127,15 +130,18 @@ class ClusterFinderMT { m_input_queues.emplace_back(std::make_unique(200)); m_output_queues.emplace_back(std::make_unique(200)); } - //TODO! Should we start automatically? + // TODO! Should we start automatically? start(); } /** * @brief Return the sink queue where all the clusters are collected - * @warning You need to empty this queue otherwise the cluster finder will wait forever + * @warning You need to empty this queue otherwise the cluster finder will + * wait forever */ - ProducerConsumerQueue> *sink() { return &m_sink; } + ProducerConsumerQueue> *sink() { + return &m_sink; + } /** * @brief Start all processing threads diff --git a/include/aare/ClusterVector.hpp b/include/aare/ClusterVector.hpp index ca2fd4d..0beae3d 100644 --- a/include/aare/ClusterVector.hpp +++ b/include/aare/ClusterVector.hpp @@ -148,6 +148,20 @@ class ClusterVector> { return sums; } + /** + * @brief Sum the pixels in the 2x2 subcluster with the biggest pixel sum in + * each cluster + * @return std::vector vector of sums for each cluster + */ //TODO if underlying container is a vector use std::for_each + std::vector sum_2x2() { + std::vector sums_2x2(m_size); + + for (size_t i = 0; i < m_size; i++) { + sums_2x2[i] = at(i).max_sum_2x2; + } + return sums_2x2; + } + /** * @brief Return the number of clusters in the vector */ diff --git a/include/aare/GainMap.hpp b/include/aare/GainMap.hpp index 9eb7c11..a60c131 100644 --- a/include/aare/GainMap.hpp +++ b/include/aare/GainMap.hpp @@ -26,7 +26,6 @@ class GainMap { typename = std::enable_if_t>> void apply_gain_map(ClusterVector &clustervec) { // in principle we need to know the size of the image for this lookup - // TODO! check orientations size_t ClusterSizeX = clustervec.cluster_size_x(); size_t ClusterSizeY = clustervec.cluster_size_y(); From a24bbd9cf93961546451094b4a269a0b93289ae4 Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Thu, 3 Apr 2025 11:56:25 +0200 Subject: [PATCH 23/51] started to do python refactoring --- python/src/cluster.hpp | 185 ++++++++++++++++++++--------------- python/src/cluster_file.hpp | 89 ++++++++++------- python/src/interpolation.hpp | 51 ++++++---- python/src/module.cpp | 19 ++-- 4 files changed, 198 insertions(+), 146 deletions(-) diff --git a/python/src/cluster.hpp b/python/src/cluster.hpp index 3db816a..5657288 100644 --- a/python/src/cluster.hpp +++ b/python/src/cluster.hpp @@ -16,149 +16,176 @@ namespace py = pybind11; using pd_type = double; -template +using namespace aare; + +template void define_cluster_vector(py::module &m, const std::string &typestr) { + + using T = typename extract_template_arguments::value_type; + auto class_name = fmt::format("ClusterVector_{}", typestr); - py::class_>(m, class_name.c_str(), py::buffer_protocol()) - .def(py::init(), - py::arg("cluster_size_x") = 3, py::arg("cluster_size_y") = 3) + py::class_>(m, class_name.c_str(), + py::buffer_protocol()) + .def(py::init(), py::arg("cluster_size_x") = 3, + py::arg("cluster_size_y") = 3) // TODO change!!! .def("push_back", - [](ClusterVector &self, int x, int y, py::array_t data) { - // auto view = make_view_2d(data); - self.push_back(x, y, reinterpret_cast(data.data())); + [](ClusterVector &self, ClusterType &cl) { + // auto view = make_view_2d(data); + self.push_back(cl); }) - .def_property_readonly("size", &ClusterVector::size) - .def("item_size", &ClusterVector::item_size) + .def_property_readonly("size", &ClusterVector::size) + .def("item_size", &ClusterVector::item_size) .def_property_readonly("fmt", - [typestr](ClusterVector &self) { + [typestr](ClusterVector &self) { return fmt::format( self.fmt_base(), self.cluster_size_x(), self.cluster_size_y(), typestr); }) .def("sum", - [](ClusterVector &self) { + [](ClusterVector &self) { auto *vec = new std::vector(self.sum()); return return_vector(vec); }) - .def("sum_2x2", [](ClusterVector &self) { - auto *vec = new std::vector(self.sum_2x2()); - return return_vector(vec); - }) - .def_property_readonly("cluster_size_x", &ClusterVector::cluster_size_x) - .def_property_readonly("cluster_size_y", &ClusterVector::cluster_size_y) - .def_property_readonly("capacity", &ClusterVector::capacity) - .def_property("frame_number", &ClusterVector::frame_number, - &ClusterVector::set_frame_number) - .def_buffer([typestr](ClusterVector &self) -> py::buffer_info { - return py::buffer_info( - self.data(), /* Pointer to buffer */ - self.item_size(), /* Size of one scalar */ - fmt::format(self.fmt_base(), self.cluster_size_x(), - self.cluster_size_y(), - typestr), /* Format descriptor */ - 1, /* Number of dimensions */ - {self.size()}, /* Buffer dimensions */ - {self.item_size()} /* Strides (in bytes) for each index */ - ); - }); + .def("sum_2x2", + [](ClusterVector &self) { + auto *vec = new std::vector(self.sum_2x2()); + return return_vector(vec); + }) + .def_property_readonly("cluster_size_x", + &ClusterVector::cluster_size_x) + .def_property_readonly("cluster_size_y", + &ClusterVector::cluster_size_y) + .def_property_readonly("capacity", + &ClusterVector::capacity) + .def_property("frame_number", &ClusterVector::frame_number, + &ClusterVector::set_frame_number) + .def_buffer( + [typestr](ClusterVector &self) -> py::buffer_info { + return py::buffer_info( + self.data(), /* Pointer to buffer */ + self.item_size(), /* Size of one scalar */ + fmt::format(self.fmt_base(), self.cluster_size_x(), + self.cluster_size_y(), + typestr), /* Format descriptor */ + 1, /* Number of dimensions */ + {self.size()}, /* Buffer dimensions */ + {self.item_size()} /* Strides (in bytes) for each index */ + ); + }); } +template void define_cluster_finder_mt_bindings(py::module &m) { - py::class_>(m, "ClusterFinderMT") + py::class_>( + m, "ClusterFinderMT") .def(py::init, Shape<2>, pd_type, size_t, size_t>(), py::arg("image_size"), py::arg("cluster_size"), py::arg("n_sigma") = 5.0, py::arg("capacity") = 2048, py::arg("n_threads") = 3) .def("push_pedestal_frame", - [](ClusterFinderMT &self, + [](ClusterFinderMT &self, py::array_t frame) { auto view = make_view_2d(frame); self.push_pedestal_frame(view); }) .def( "find_clusters", - [](ClusterFinderMT &self, + [](ClusterFinderMT &self, py::array_t frame, uint64_t frame_number) { auto view = make_view_2d(frame); self.find_clusters(view, frame_number); return; }, py::arg(), py::arg("frame_number") = 0) - .def("clear_pedestal", &ClusterFinderMT::clear_pedestal) - .def("sync", &ClusterFinderMT::sync) - .def("stop", &ClusterFinderMT::stop) - .def("start", &ClusterFinderMT::start) - .def("pedestal", - [](ClusterFinderMT &self, size_t thread_index) { - auto pd = new NDArray{}; - *pd = self.pedestal(thread_index); - return return_image_data(pd); - },py::arg("thread_index") = 0) - .def("noise", - [](ClusterFinderMT &self, size_t thread_index) { - auto arr = new NDArray{}; - *arr = self.noise(thread_index); - return return_image_data(arr); - },py::arg("thread_index") = 0); + .def("clear_pedestal", + &ClusterFinderMT::clear_pedestal) + .def("sync", &ClusterFinderMT::sync) + .def("stop", &ClusterFinderMT::stop) + .def("start", &ClusterFinderMT::start) + .def( + "pedestal", + [](ClusterFinderMT &self, + size_t thread_index) { + auto pd = new NDArray{}; + *pd = self.pedestal(thread_index); + return return_image_data(pd); + }, + py::arg("thread_index") = 0) + .def( + "noise", + [](ClusterFinderMT &self, + size_t thread_index) { + auto arr = new NDArray{}; + *arr = self.noise(thread_index); + return return_image_data(arr); + }, + py::arg("thread_index") = 0); } +template void define_cluster_collector_bindings(py::module &m) { - py::class_(m, "ClusterCollector") - .def(py::init *>()) - .def("stop", &ClusterCollector::stop) + py::class_>(m, "ClusterCollector") + .def(py::init *>()) + .def("stop", &ClusterCollector::stop) .def( "steal_clusters", - [](ClusterCollector &self) { - auto v = - new std::vector>(self.steal_clusters()); + [](ClusterCollector &self) { + auto v = new std::vector>( + self.steal_clusters()); return v; }, py::return_value_policy::take_ownership); } +template void define_cluster_file_sink_bindings(py::module &m) { - py::class_(m, "ClusterFileSink") - .def(py::init *, + py::class_>(m, "ClusterFileSink") + .def(py::init *, const std::filesystem::path &>()) - .def("stop", &ClusterFileSink::stop); + .def("stop", &ClusterFileSink::stop); } +template void define_cluster_finder_bindings(py::module &m) { - py::class_>(m, "ClusterFinder") + py::class_>(m, + "ClusterFinder") .def(py::init, Shape<2>, pd_type, size_t>(), py::arg("image_size"), py::arg("cluster_size"), py::arg("n_sigma") = 5.0, py::arg("capacity") = 1'000'000) .def("push_pedestal_frame", - [](ClusterFinder &self, + [](ClusterFinder &self, py::array_t frame) { auto view = make_view_2d(frame); self.push_pedestal_frame(view); }) - .def("clear_pedestal", &ClusterFinder::clear_pedestal) - .def_property_readonly("pedestal", - [](ClusterFinder &self) { - auto pd = new NDArray{}; - *pd = self.pedestal(); - return return_image_data(pd); - }) - .def_property_readonly("noise", - [](ClusterFinder &self) { - auto arr = new NDArray{}; - *arr = self.noise(); - return return_image_data(arr); - }) + .def("clear_pedestal", + &ClusterFinder::clear_pedestal) + .def_property_readonly( + "pedestal", + [](ClusterFinder &self) { + auto pd = new NDArray{}; + *pd = self.pedestal(); + return return_image_data(pd); + }) + .def_property_readonly( + "noise", + [](ClusterFinder &self) { + auto arr = new NDArray{}; + *arr = self.noise(); + return return_image_data(arr); + }) .def( "steal_clusters", - [](ClusterFinder &self, + [](ClusterFinder &self, bool realloc_same_capacity) { - auto v = new ClusterVector( + auto v = new ClusterVector( self.steal_clusters(realloc_same_capacity)); return v; }, py::arg("realloc_same_capacity") = false) .def( "find_clusters", - [](ClusterFinder &self, + [](ClusterFinder &self, py::array_t frame, uint64_t frame_number) { auto view = make_view_2d(frame); self.find_clusters(view, frame_number); @@ -167,7 +194,7 @@ void define_cluster_finder_bindings(py::module &m) { py::arg(), py::arg("frame_number") = 0); m.def("hitmap", - [](std::array image_size, ClusterVector &cv) { + [](std::array image_size, ClusterVector &cv) { py::array_t hitmap(image_size); auto r = hitmap.mutable_unchecked<2>(); diff --git a/python/src/cluster_file.hpp b/python/src/cluster_file.hpp index b807712..576c3bb 100644 --- a/python/src/cluster_file.hpp +++ b/python/src/cluster_file.hpp @@ -10,69 +10,86 @@ #include #include -//Disable warnings for unused parameters, as we ignore some -//in the __exit__ method +// Disable warnings for unused parameters, as we ignore some +// in the __exit__ method #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" - namespace py = pybind11; using namespace ::aare; +template void define_cluster_file_io_bindings(py::module &m) { PYBIND11_NUMPY_DTYPE(Cluster3x3, x, y, data); - py::class_(m, "ClusterFile") + py::class_>(m, "ClusterFile") .def(py::init(), py::arg(), py::arg("chunk_size") = 1000, py::arg("mode") = "r") - .def("read_clusters", - [](ClusterFile &self, size_t n_clusters) { - auto v = new ClusterVector(self.read_clusters(n_clusters)); + .def( + "read_clusters", + [](ClusterFile &self, size_t n_clusters) { + auto v = new ClusterVector( + self.read_clusters(n_clusters)); return v; - },py::return_value_policy::take_ownership) - .def("read_clusters", - [](ClusterFile &self, size_t n_clusters, ROI roi) { - auto v = new ClusterVector(self.read_clusters(n_clusters, roi)); - return v; - },py::return_value_policy::take_ownership) + }, + py::return_value_policy::take_ownership) + .def( + "read_clusters", + [](ClusterFile &self, size_t n_clusters, ROI roi) { + auto v = new ClusterVector( + self.read_clusters(n_clusters, roi)); + return v; + }, + py::return_value_policy::take_ownership) .def("read_frame", - [](ClusterFile &self) { - auto v = new ClusterVector(self.read_frame()); - return v; + [](ClusterFile &self) { + auto v = new ClusterVector(self.read_frame()); + return v; }) - .def("set_roi", &ClusterFile::set_roi) - .def("set_noise_map", [](ClusterFile &self, py::array_t noise_map) { - auto view = make_view_2d(noise_map); - self.set_noise_map(view); - }) - .def("set_gain_map", [](ClusterFile &self, py::array_t gain_map) { - auto view = make_view_2d(gain_map); - self.set_gain_map(view); - }) - .def("close", &ClusterFile::close) - .def("write_frame", &ClusterFile::write_frame) - .def("__enter__", [](ClusterFile &self) { return &self; }) + .def("set_roi", &ClusterFile::set_roi) + .def( + "set_noise_map", + [](ClusterFile &self, py::array_t noise_map) { + auto view = make_view_2d(noise_map); + self.set_noise_map(view); + }) + + .def("set_gain_map", + [](ClusterFile &self, py::array_t gain_map) { + auto view = make_view_2d(gain_map); + self.set_gain_map(view); + }) + + // void set_gain_map(const GainMap &gain_map); //TODO do i need a + // gainmap constructor? + + .def("close", &ClusterFile::close) + .def("write_frame", &ClusterFile::write_frame) + .def("__enter__", [](ClusterFile &self) { return &self; }) .def("__exit__", - [](ClusterFile &self, + [](ClusterFile &self, const std::optional &exc_type, const std::optional &exc_value, const std::optional &traceback) { self.close(); }) - .def("__iter__", [](ClusterFile &self) { return &self; }) - .def("__next__", [](ClusterFile &self) { - auto v = new ClusterVector(self.read_clusters(self.chunk_size())); + .def("__iter__", [](ClusterFile &self) { return &self; }) + .def("__next__", [](ClusterFile &self) { + auto v = new ClusterVector( + self.read_clusters(self.chunk_size())); if (v->size() == 0) { throw py::stop_iteration(); } return v; }); - m.def("calculate_eta2", []( aare::ClusterVector &clusters) { - auto eta2 = new NDArray(calculate_eta2(clusters)); - return return_image_data(eta2); - }); + /* + m.def("calculate_eta2", []( aare::ClusterVector &clusters) { + auto eta2 = new NDArray(calculate_eta2(clusters)); + return return_image_data(eta2); + }); + */ //add in different file } #pragma GCC diagnostic pop \ No newline at end of file diff --git a/python/src/interpolation.hpp b/python/src/interpolation.hpp index 02742e1..47b5203 100644 --- a/python/src/interpolation.hpp +++ b/python/src/interpolation.hpp @@ -8,31 +8,40 @@ #include namespace py = pybind11; + void define_interpolation_bindings(py::module &m) { - PYBIND11_NUMPY_DTYPE(aare::Photon, x,y,energy); + PYBIND11_NUMPY_DTYPE(aare::Photon, x, y, energy); py::class_(m, "Interpolator") - .def(py::init([](py::array_t etacube, py::array_t xbins, - py::array_t ybins, py::array_t ebins) { - return Interpolator(make_view_3d(etacube), make_view_1d(xbins), - make_view_1d(ybins), make_view_1d(ebins)); - })) - .def("get_ietax", [](Interpolator& self){ - auto*ptr = new NDArray{}; - *ptr = self.get_ietax(); - return return_image_data(ptr); - }) - .def("get_ietay", [](Interpolator& self){ - auto*ptr = new NDArray{}; - *ptr = self.get_ietay(); - return return_image_data(ptr); - }) - .def("interpolate", [](Interpolator& self, const ClusterVector& clusters){ - auto photons = self.interpolate(clusters); - auto* ptr = new std::vector{photons}; - return return_vector(ptr); - }); + .def(py::init( + [](py::array_t + etacube, + py::array_t xbins, py::array_t ybins, + py::array_t ebins) { + return Interpolator(make_view_3d(etacube), make_view_1d(xbins), + make_view_1d(ybins), make_view_1d(ebins)); + })) + .def("get_ietax", + [](Interpolator &self) { + auto *ptr = new NDArray{}; + *ptr = self.get_ietax(); + return return_image_data(ptr); + }) + .def("get_ietay", + [](Interpolator &self) { + auto *ptr = new NDArray{}; + *ptr = self.get_ietay(); + return return_image_data(ptr); + }) + + // TODO take care of clustertype template + .def("interpolate", + [](Interpolator &self, const ClusterVector &clusters) { + auto photons = self.interpolate(clusters); + auto *ptr = new std::vector{photons}; + return return_vector(ptr); + }); // TODO! Evaluate without converting to double m.def( diff --git a/python/src/module.cpp b/python/src/module.cpp index 43f48ba..ba681be 100644 --- a/python/src/module.cpp +++ b/python/src/module.cpp @@ -1,17 +1,17 @@ -//Files with bindings to the different classes -#include "file.hpp" -#include "raw_file.hpp" -#include "ctb_raw_file.hpp" -#include "raw_master_file.hpp" -#include "var_cluster.hpp" -#include "pixel_map.hpp" -#include "pedestal.hpp" +// Files with bindings to the different classes #include "cluster.hpp" #include "cluster_file.hpp" +#include "ctb_raw_file.hpp" +#include "file.hpp" #include "fit.hpp" #include "interpolation.hpp" +#include "pedestal.hpp" +#include "pixel_map.hpp" +#include "raw_file.hpp" +#include "raw_master_file.hpp" +#include "var_cluster.hpp" -//Pybind stuff +// Pybind stuff #include #include @@ -33,5 +33,4 @@ PYBIND11_MODULE(_aare, m) { define_cluster_file_sink_bindings(m); define_fit_bindings(m); define_interpolation_bindings(m); - } \ No newline at end of file From 248d25486fc0223498742215dbe4bd3d6736512c Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Thu, 3 Apr 2025 16:38:12 +0200 Subject: [PATCH 24/51] refactored python files --- include/aare/CalculateEta.hpp | 13 ++++--- include/aare/Cluster.hpp | 4 +- include/aare/ClusterFinder.hpp | 11 ++++-- include/aare/ClusterFinderMT.hpp | 10 ++--- include/aare/GainMap.hpp | 2 +- python/src/cluster.hpp | 53 +++++++++++++++----------- python/src/cluster_file.hpp | 22 ++++++----- python/src/interpolation.hpp | 64 +++++++++++++++++++------------- python/src/module.cpp | 49 +++++++++++++++++++++--- 9 files changed, 151 insertions(+), 77 deletions(-) diff --git a/include/aare/CalculateEta.hpp b/include/aare/CalculateEta.hpp index 86871c9..0aab540 100644 --- a/include/aare/CalculateEta.hpp +++ b/include/aare/CalculateEta.hpp @@ -35,7 +35,8 @@ template struct Eta2 { /** * @brief Calculate the eta2 values for all clusters in a Clsutervector */ -template >> +template >> NDArray calculate_eta2(const ClusterVector &clusters) { NDArray eta2({static_cast(clusters.size()), 2}); @@ -70,16 +71,18 @@ calculate_eta2(const Cluster &cl) { cl.data[index_bottom_left_max_2x2_subcluster + 1]) != 0) eta.x = static_cast( cl.data[index_bottom_left_max_2x2_subcluster + 1]) / - (cl.data[index_bottom_left_max_2x2_subcluster] + - cl.data[index_bottom_left_max_2x2_subcluster + 1]); + static_cast( + (cl.data[index_bottom_left_max_2x2_subcluster] + + cl.data[index_bottom_left_max_2x2_subcluster + 1])); if ((cl.data[index_bottom_left_max_2x2_subcluster] + cl.data[index_bottom_left_max_2x2_subcluster + ClusterSizeX]) != 0) eta.y = static_cast( cl.data[index_bottom_left_max_2x2_subcluster + ClusterSizeX]) / - (cl.data[index_bottom_left_max_2x2_subcluster] + - cl.data[index_bottom_left_max_2x2_subcluster + ClusterSizeX]); + static_cast( + (cl.data[index_bottom_left_max_2x2_subcluster] + + cl.data[index_bottom_left_max_2x2_subcluster + ClusterSizeX])); eta.c = c; // TODO only supported for 2x2 and 3x3 clusters -> at least no // underyling enum class diff --git a/include/aare/Cluster.hpp b/include/aare/Cluster.hpp index ca2e01f..a47edf0 100644 --- a/include/aare/Cluster.hpp +++ b/include/aare/Cluster.hpp @@ -100,8 +100,8 @@ struct is_cluster> : std::true_type {}; // Cluster template constexpr bool is_cluster_v = is_cluster::value; -template -// typename = std::enable_if_t>> +template >> struct extract_template_arguments; // Forward declaration // helper struct to extract template argument diff --git a/include/aare/ClusterFinder.hpp b/include/aare/ClusterFinder.hpp index 120d39d..8c3540a 100644 --- a/include/aare/ClusterFinder.hpp +++ b/include/aare/ClusterFinder.hpp @@ -139,7 +139,8 @@ class ClusterFinder { iy + ir >= 0 && iy + ir < frame.shape(0)) { CT tmp = static_cast(frame(iy + ir, ix + ic)) - - m_pedestal.mean(iy + ir, ix + ic); + static_cast( + m_pedestal.mean(iy + ir, ix + ic)); cluster_data[i] = tmp; // Watch for out of bounds access i++; @@ -147,9 +148,13 @@ class ClusterFinder { } } + ClusterType new_cluster{}; + new_cluster.x = ix; + new_cluster.y = iy; + std::copy(cluster_data.begin(), cluster_data.end(), + new_cluster.data); // Add the cluster to the output ClusterVector - m_clusters.push_back( - ClusterType{ix, iy, cluster_data.data()}); + m_clusters.push_back(new_cluster); } } } diff --git a/include/aare/ClusterFinderMT.hpp b/include/aare/ClusterFinderMT.hpp index 62046b7..75b6497 100644 --- a/include/aare/ClusterFinderMT.hpp +++ b/include/aare/ClusterFinderMT.hpp @@ -117,14 +117,14 @@ class ClusterFinderMT { * expected number of clusters in a frame per frame. * @param n_threads number of threads to use */ - ClusterFinderMT(Shape<2> image_size, Shape<2> cluster_size, - PEDESTAL_TYPE nSigma = 5.0, size_t capacity = 2000, - size_t n_threads = 3) + ClusterFinderMT(Shape<2> image_size, PEDESTAL_TYPE nSigma = 5.0, + size_t capacity = 2000, size_t n_threads = 3) : m_n_threads(n_threads) { for (size_t i = 0; i < n_threads; i++) { m_cluster_finders.push_back( - std::make_unique>( - image_size, cluster_size, nSigma, capacity)); + std::make_unique< + ClusterFinder>( + image_size, nSigma, capacity)); } for (size_t i = 0; i < n_threads; i++) { m_input_queues.emplace_back(std::make_unique(200)); diff --git a/include/aare/GainMap.hpp b/include/aare/GainMap.hpp index a60c131..41acb33 100644 --- a/include/aare/GainMap.hpp +++ b/include/aare/GainMap.hpp @@ -41,7 +41,7 @@ class GainMap { for (size_t j = 0; j < ClusterSizeX * ClusterSizeY; j++) { size_t x = cl.x + j % ClusterSizeX - index_cluster_center_x; size_t y = cl.y + j / ClusterSizeX - index_cluster_center_y; - cl.data[j] = static_cast(cl.data[j] * m_gain_map(y, x)); + cl.data[j] = cl.data[j] * static_cast(m_gain_map(y, x)); } } else { memset(cl.data, 0, diff --git a/python/src/cluster.hpp b/python/src/cluster.hpp index 5657288..fb3d1da 100644 --- a/python/src/cluster.hpp +++ b/python/src/cluster.hpp @@ -21,9 +21,8 @@ using namespace aare; template void define_cluster_vector(py::module &m, const std::string &typestr) { - using T = typename extract_template_arguments::value_type; - auto class_name = fmt::format("ClusterVector_{}", typestr); + py::class_>(m, class_name.c_str(), py::buffer_protocol()) .def(py::init(), py::arg("cluster_size_x") = 3, @@ -41,6 +40,7 @@ void define_cluster_vector(py::module &m, const std::string &typestr) { self.fmt_base(), self.cluster_size_x(), self.cluster_size_y(), typestr); }) + /* .def("sum", [](ClusterVector &self) { auto *vec = new std::vector(self.sum()); @@ -51,6 +51,7 @@ void define_cluster_vector(py::module &m, const std::string &typestr) { auto *vec = new std::vector(self.sum_2x2()); return return_vector(vec); }) + */ .def_property_readonly("cluster_size_x", &ClusterVector::cluster_size_x) .def_property_readonly("cluster_size_y", @@ -75,13 +76,16 @@ void define_cluster_vector(py::module &m, const std::string &typestr) { } template -void define_cluster_finder_mt_bindings(py::module &m) { +void define_cluster_finder_mt_bindings(py::module &m, + const std::string &typestr) { + + auto class_name = fmt::format("ClusterFinderMT_{}", typestr); + py::class_>( - m, "ClusterFinderMT") - .def(py::init, Shape<2>, pd_type, size_t, size_t>(), - py::arg("image_size"), py::arg("cluster_size"), - py::arg("n_sigma") = 5.0, py::arg("capacity") = 2048, - py::arg("n_threads") = 3) + m, class_name.c_str()) + .def(py::init, 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) .def("push_pedestal_frame", [](ClusterFinderMT &self, py::array_t frame) { @@ -123,8 +127,12 @@ void define_cluster_finder_mt_bindings(py::module &m) { } template -void define_cluster_collector_bindings(py::module &m) { - py::class_>(m, "ClusterCollector") +void define_cluster_collector_bindings(py::module &m, + const std::string &typestr) { + + auto class_name = fmt::format("ClusterCollector_{}", typestr); + + py::class_>(m, class_name.c_str()) .def(py::init *>()) .def("stop", &ClusterCollector::stop) .def( @@ -138,19 +146,25 @@ void define_cluster_collector_bindings(py::module &m) { } template -void define_cluster_file_sink_bindings(py::module &m) { - py::class_>(m, "ClusterFileSink") +void define_cluster_file_sink_bindings(py::module &m, + const std::string &typestr) { + + auto class_name = fmt::format("ClusterFileSink_{}", typestr); + + py::class_>(m, class_name.c_str()) .def(py::init *, const std::filesystem::path &>()) .def("stop", &ClusterFileSink::stop); } template -void define_cluster_finder_bindings(py::module &m) { - py::class_>(m, - "ClusterFinder") - .def(py::init, Shape<2>, pd_type, size_t>(), - py::arg("image_size"), py::arg("cluster_size"), +void define_cluster_finder_bindings(py::module &m, const std::string &typestr) { + + auto class_name = fmt::format("ClusterFinder_{}", typestr); + + py::class_>( + m, class_name.c_str()) + .def(py::init, 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 &self, @@ -213,9 +227,6 @@ void define_cluster_finder_bindings(py::module &m) { } return hitmap; }); - define_cluster_vector(m, "i"); - define_cluster_vector(m, "d"); - define_cluster_vector(m, "f"); py::class_(m, "DynamicCluster", py::buffer_protocol()) .def(py::init()) @@ -233,4 +244,4 @@ void define_cluster_finder_bindings(py::module &m) { return ""; }); -} \ No newline at end of file +} diff --git a/python/src/cluster_file.hpp b/python/src/cluster_file.hpp index 576c3bb..151644c 100644 --- a/python/src/cluster_file.hpp +++ b/python/src/cluster_file.hpp @@ -1,3 +1,4 @@ +#include "aare/CalculateEta.hpp" #include "aare/ClusterFile.hpp" #include "aare/defs.hpp" @@ -19,10 +20,14 @@ namespace py = pybind11; using namespace ::aare; template -void define_cluster_file_io_bindings(py::module &m) { - PYBIND11_NUMPY_DTYPE(Cluster3x3, x, y, data); +void define_cluster_file_io_bindings(py::module &m, + const std::string &typestr) { + // PYBIND11_NUMPY_DTYPE(Cluster, x, y, + // data); // is this used - maybe use as cluster type - py::class_>(m, "ClusterFile") + auto class_name = fmt::format("ClusterFile_{}", typestr); + + py::class_>(m, class_name.c_str()) .def(py::init(), py::arg(), py::arg("chunk_size") = 1000, py::arg("mode") = "r") @@ -84,12 +89,11 @@ void define_cluster_file_io_bindings(py::module &m) { return v; }); - /* - m.def("calculate_eta2", []( aare::ClusterVector &clusters) { - auto eta2 = new NDArray(calculate_eta2(clusters)); - return return_image_data(eta2); - }); - */ //add in different file + m.def("calculate_eta2", + [](const aare::ClusterVector &clusters) { + auto eta2 = new NDArray(calculate_eta2(clusters)); + return return_image_data(eta2); + }); } #pragma GCC diagnostic pop \ No newline at end of file diff --git a/python/src/interpolation.hpp b/python/src/interpolation.hpp index 47b5203..cc14553 100644 --- a/python/src/interpolation.hpp +++ b/python/src/interpolation.hpp @@ -9,39 +9,53 @@ namespace py = pybind11; +template +void register_interpolate(py::class_ &interpolator) { + std::string name = + fmt::format("interpolate_{}", typeid(ClusterType).name()); + + interpolator.def(name.c_str(), + [](aare::Interpolator &self, + const ClusterVector &clusters) { + auto photons = self.interpolate(clusters); + auto *ptr = new std::vector{photons}; + return return_vector(ptr); + }); +} + void define_interpolation_bindings(py::module &m) { PYBIND11_NUMPY_DTYPE(aare::Photon, x, y, energy); - py::class_(m, "Interpolator") - .def(py::init( - [](py::array_t - etacube, - py::array_t xbins, py::array_t ybins, - py::array_t ebins) { + auto interpolator = + py::class_(m, "Interpolator") + .def(py::init([](py::array_t + etacube, + py::array_t xbins, + py::array_t ybins, + py::array_t ebins) { return Interpolator(make_view_3d(etacube), make_view_1d(xbins), make_view_1d(ybins), make_view_1d(ebins)); })) - .def("get_ietax", - [](Interpolator &self) { - auto *ptr = new NDArray{}; - *ptr = self.get_ietax(); - return return_image_data(ptr); - }) - .def("get_ietay", - [](Interpolator &self) { - auto *ptr = new NDArray{}; - *ptr = self.get_ietay(); - return return_image_data(ptr); - }) + .def("get_ietax", + [](Interpolator &self) { + auto *ptr = new NDArray{}; + *ptr = self.get_ietax(); + return return_image_data(ptr); + }) + .def("get_ietay", [](Interpolator &self) { + auto *ptr = new NDArray{}; + *ptr = self.get_ietay(); + return return_image_data(ptr); + }); - // TODO take care of clustertype template - .def("interpolate", - [](Interpolator &self, const ClusterVector &clusters) { - auto photons = self.interpolate(clusters); - auto *ptr = new std::vector{photons}; - return return_vector(ptr); - }); + register_interpolate>(interpolator); + register_interpolate>(interpolator); + register_interpolate>(interpolator); + register_interpolate>(interpolator); + register_interpolate>(interpolator); + register_interpolate>(interpolator); // TODO! Evaluate without converting to double m.def( diff --git a/python/src/module.cpp b/python/src/module.cpp index ba681be..4df5d77 100644 --- a/python/src/module.cpp +++ b/python/src/module.cpp @@ -26,11 +26,48 @@ PYBIND11_MODULE(_aare, m) { define_pixel_map_bindings(m); define_pedestal_bindings(m, "Pedestal_d"); define_pedestal_bindings(m, "Pedestal_f"); - define_cluster_finder_bindings(m); - define_cluster_finder_mt_bindings(m); - define_cluster_file_io_bindings(m); - define_cluster_collector_bindings(m); - define_cluster_file_sink_bindings(m); define_fit_bindings(m); define_interpolation_bindings(m); -} \ No newline at end of file + + define_cluster_file_io_bindings>(m, "Cluster3x3i"); + define_cluster_file_io_bindings>(m, "Cluster3x3d"); + define_cluster_file_io_bindings>(m, "Cluster3x3f"); + define_cluster_file_io_bindings>(m, "Cluster2x2i"); + define_cluster_file_io_bindings>(m, "Cluster2x2f"); + define_cluster_file_io_bindings>(m, "Cluster2x2d"); + + define_cluster_vector>(m, "Cluster3x3i"); + define_cluster_vector>(m, "Cluster3x3d"); + define_cluster_vector>(m, "Cluster3x3f"); + define_cluster_vector>(m, "Cluster2x2i"); + define_cluster_vector>(m, "Cluster2x2d"); + define_cluster_vector>(m, "Cluster2x2f"); + + define_cluster_finder_bindings>(m, "Cluster3x3i"); + define_cluster_finder_bindings>(m, "Cluster3x3d"); + define_cluster_finder_bindings>(m, "Cluster3x3f"); + define_cluster_finder_bindings>(m, "Cluster2x2i"); + define_cluster_finder_bindings>(m, "Cluster2x2d"); + define_cluster_finder_bindings>(m, "Cluster2x2f"); + + define_cluster_finder_mt_bindings>(m, "Cluster3x3i"); + define_cluster_finder_mt_bindings>(m, "Cluster3x3d"); + define_cluster_finder_mt_bindings>(m, "Cluster3x3f"); + define_cluster_finder_mt_bindings>(m, "Cluster2x2i"); + define_cluster_finder_mt_bindings>(m, "Cluster2x2d"); + define_cluster_finder_mt_bindings>(m, "Cluster2x2f"); + + define_cluster_file_sink_bindings>(m, "Cluster3x3i"); + define_cluster_file_sink_bindings>(m, "Cluster3x3d"); + define_cluster_file_sink_bindings>(m, "Cluster3x3f"); + define_cluster_file_sink_bindings>(m, "Cluster2x2i"); + define_cluster_file_sink_bindings>(m, "Cluster2x2d"); + define_cluster_file_sink_bindings>(m, "Cluster2x2f"); + + define_cluster_collector_bindings>(m, "Cluster3x3i"); + define_cluster_collector_bindings>(m, "Cluster3x3f"); + define_cluster_collector_bindings>(m, "Cluster3x3d"); + define_cluster_collector_bindings>(m, "Cluster2x2i"); + define_cluster_collector_bindings>(m, "Cluster2x2f"); + define_cluster_collector_bindings>(m, "Cluster2x2d"); +} From e24ed684166a6c4b927ca65836c72eeec93e40ec Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Thu, 3 Apr 2025 16:50:02 +0200 Subject: [PATCH 25/51] fixed include --- include/aare/Cluster.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/aare/Cluster.hpp b/include/aare/Cluster.hpp index a47edf0..e2cfe99 100644 --- a/include/aare/Cluster.hpp +++ b/include/aare/Cluster.hpp @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include #include From 885309d97ce6295b8304533f4a29a96fe253866f Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Thu, 3 Apr 2025 17:14:28 +0200 Subject: [PATCH 26/51] fix build --- include/aare/Interpolator.hpp | 4 ++-- src/Interpolator.cpp | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/include/aare/Interpolator.hpp b/include/aare/Interpolator.hpp index 5843046..88f127e 100644 --- a/include/aare/Interpolator.hpp +++ b/include/aare/Interpolator.hpp @@ -5,6 +5,7 @@ #include "aare/ClusterVector.hpp" #include "aare/NDArray.hpp" #include "aare/NDView.hpp" + namespace aare { struct Photon { @@ -27,8 +28,7 @@ class Interpolator { NDArray get_ietax() { return m_ietax; } NDArray get_ietay() { return m_ietay; } - template >> + template std::vector interpolate(const ClusterVector &clusters); }; diff --git a/src/Interpolator.cpp b/src/Interpolator.cpp index e4f8e5c..3680522 100644 --- a/src/Interpolator.cpp +++ b/src/Interpolator.cpp @@ -57,8 +57,7 @@ Interpolator::Interpolator(NDView etacube, NDView xbins, // TODO: generalize to support any clustertype!!! otherwise add std::enable_if_t // to only take Cluster2x2 and Cluster3x3 -template >> +template std::vector Interpolator::interpolate(const ClusterVector &clusters) { std::vector photons; From 9de84a7f87b27346c07b0fc69a0d366ca416dd72 Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Fri, 4 Apr 2025 17:19:15 +0200 Subject: [PATCH 27/51] added some python tests --- include/aare/Cluster.hpp | 1 + include/aare/ClusterFile.hpp | 4 +- include/aare/ClusterVector.hpp | 4 ++ include/aare/Interpolator.hpp | 99 +++++++++++++++++++++++++++++++++- python/src/cluster.hpp | 94 ++++++++++++++++++++++---------- python/src/cluster_file.hpp | 8 --- python/src/interpolation.hpp | 18 +++---- python/src/module.cpp | 7 +++ python/src/np_helper.hpp | 15 +++--- python/tests/test_Cluster.py | 64 ++++++++++++++++++++++ src/ClusterVector.test.cpp | 4 ++ src/Interpolator.cpp | 97 --------------------------------- 12 files changed, 264 insertions(+), 151 deletions(-) create mode 100644 python/tests/test_Cluster.py diff --git a/include/aare/Cluster.hpp b/include/aare/Cluster.hpp index e2cfe99..a2c9b55 100644 --- a/include/aare/Cluster.hpp +++ b/include/aare/Cluster.hpp @@ -40,6 +40,7 @@ struct Cluster { constexpr size_t num_2x2_subclusters = (ClusterSizeX - 1) * (ClusterSizeY - 1); + std::array sum_2x2_subcluster; for (size_t i = 0; i < ClusterSizeY - 1; ++i) { for (size_t j = 0; j < ClusterSizeX - 1; ++j) diff --git a/include/aare/ClusterFile.hpp b/include/aare/ClusterFile.hpp index bc0ebd1..ff5d338 100644 --- a/include/aare/ClusterFile.hpp +++ b/include/aare/ClusterFile.hpp @@ -36,7 +36,7 @@ uint32_t number_of_clusters * etc. */ template , bool>> + typename Enable = std::enable_if_t>> class ClusterFile { FILE *fp{}; uint32_t m_num_left{}; /*Number of photons left in frame*/ @@ -70,8 +70,6 @@ class ClusterFile { */ ClusterVector read_clusters(size_t n_clusters); - ClusterVector read_clusters(size_t n_clusters, ROI roi); - /** * @brief Read a single frame from the file and return the clusters. The * cluster vector will have the frame number set. diff --git a/include/aare/ClusterVector.hpp b/include/aare/ClusterVector.hpp index 0beae3d..f3b55be 100644 --- a/include/aare/ClusterVector.hpp +++ b/include/aare/ClusterVector.hpp @@ -133,6 +133,7 @@ class ClusterVector> { * @brief Sum the pixels in each cluster * @return std::vector vector of sums for each cluster */ + /* std::vector sum() { std::vector sums(m_size); const size_t stride = item_size(); @@ -147,12 +148,14 @@ class ClusterVector> { } return sums; } + */ /** * @brief Sum the pixels in the 2x2 subcluster with the biggest pixel sum in * each cluster * @return std::vector vector of sums for each cluster */ //TODO if underlying container is a vector use std::for_each + /* std::vector sum_2x2() { std::vector sums_2x2(m_size); @@ -161,6 +164,7 @@ class ClusterVector> { } return sums_2x2; } + */ /** * @brief Return the number of clusters in the vector diff --git a/include/aare/Interpolator.hpp b/include/aare/Interpolator.hpp index 88f127e..7e3a1c1 100644 --- a/include/aare/Interpolator.hpp +++ b/include/aare/Interpolator.hpp @@ -1,10 +1,12 @@ #pragma once +#include "aare/CalculateEta.hpp" #include "aare/Cluster.hpp" #include "aare/ClusterFile.hpp" //Cluster_3x3 #include "aare/ClusterVector.hpp" #include "aare/NDArray.hpp" #include "aare/NDView.hpp" +#include "aare/algorithm.hpp" namespace aare { @@ -28,8 +30,103 @@ class Interpolator { NDArray get_ietax() { return m_ietax; } NDArray get_ietay() { return m_ietay; } - template + template >> std::vector interpolate(const ClusterVector &clusters); }; +// TODO: generalize to support any clustertype!!! otherwise add std::enable_if_t +// to only take Cluster2x2 and Cluster3x3 +template +std::vector +Interpolator::interpolate(const ClusterVector &clusters) { + std::vector photons; + photons.reserve(clusters.size()); + + if (clusters.cluster_size_x() == 3 || clusters.cluster_size_y() == 3) { + for (size_t i = 0; i < clusters.size(); i++) { + + auto cluster = clusters.at(i); + auto eta = calculate_eta2(cluster); + + Photon photon; + photon.x = cluster.x; + photon.y = cluster.y; + photon.energy = eta.sum; + + // auto ie = nearest_index(m_energy_bins, photon.energy)-1; + // auto ix = nearest_index(m_etabinsx, eta.x)-1; + // auto iy = nearest_index(m_etabinsy, eta.y)-1; + // Finding the index of the last element that is smaller + // should work fine as long as we have many bins + auto ie = last_smaller(m_energy_bins, photon.energy); + auto ix = last_smaller(m_etabinsx, eta.x); + auto iy = last_smaller(m_etabinsy, eta.y); + + // fmt::print("ex: {}, ix: {}, iy: {}\n", ie, ix, iy); + + double dX, dY; + // cBottomLeft = 0, + // cBottomRight = 1, + // cTopLeft = 2, + // cTopRight = 3 + switch (eta.c) { + case cTopLeft: + dX = -1.; + dY = 0; + break; + case cTopRight:; + dX = 0; + dY = 0; + break; + case cBottomLeft: + dX = -1.; + dY = -1.; + break; + case cBottomRight: + dX = 0.; + dY = -1.; + break; + } + photon.x += m_ietax(ix, iy, ie) * 2 + dX; + photon.y += m_ietay(ix, iy, ie) * 2 + dY; + photons.push_back(photon); + } + } else if (clusters.cluster_size_x() == 2 || + clusters.cluster_size_y() == 2) { + for (size_t i = 0; i < clusters.size(); i++) { + auto cluster = clusters.at(i); + auto eta = calculate_eta2(cluster); + + Photon photon; + photon.x = cluster.x; + photon.y = cluster.y; + photon.energy = eta.sum; + + // Now do some actual interpolation. + // Find which energy bin the cluster is in + // auto ie = nearest_index(m_energy_bins, photon.energy)-1; + // auto ix = nearest_index(m_etabinsx, eta.x)-1; + // auto iy = nearest_index(m_etabinsy, eta.y)-1; + // Finding the index of the last element that is smaller + // should work fine as long as we have many bins + auto ie = last_smaller(m_energy_bins, photon.energy); + auto ix = last_smaller(m_etabinsx, eta.x); + auto iy = last_smaller(m_etabinsy, eta.y); + + photon.x += m_ietax(ix, iy, ie) * + 2; // eta goes between 0 and 1 but we could move the hit + // anywhere in the 2x2 + photon.y += m_ietay(ix, iy, ie) * 2; + photons.push_back(photon); + } + + } else { + throw std::runtime_error( + "Only 3x3 and 2x2 clusters are supported for interpolation"); + } + + return photons; +} + } // namespace aare \ No newline at end of file diff --git a/python/src/cluster.hpp b/python/src/cluster.hpp index fb3d1da..7dcb338 100644 --- a/python/src/cluster.hpp +++ b/python/src/cluster.hpp @@ -18,20 +18,81 @@ using pd_type = double; using namespace aare; +template +void define_cluster(py::module &m, const std::string &typestr) { + auto class_name = fmt::format("Cluster{}", typestr); + + using ClusterType = + Cluster; + py::class_>( + m, class_name.c_str()) + + .def(py::init([](uint8_t x, uint8_t y, py::array_t data) { + py::buffer_info buf_info = data.request(); + Type *ptr = static_cast(buf_info.ptr); + Cluster cluster; + cluster.x = x; + cluster.y = y; + std::copy(ptr, ptr + ClusterSizeX * ClusterSizeY, + cluster.data); // Copy array contents + return cluster; + })) + + //.def(py::init<>()) + .def_readwrite("x", &ClusterType::x) + .def_readwrite("y", &ClusterType::y) + .def_property( + "data", + [](ClusterType &c) -> py::array { + return py::array(py::buffer_info( + c.data, sizeof(Type), + py::format_descriptor::format(), // Type + // format + 1, // Number of dimensions + {static_cast(ClusterSizeX * + ClusterSizeY)}, // Shape (flattened) + {sizeof(Type)} // Stride (step size between elements) + )); + }, + [](ClusterType &c, py::array_t arr) { + py::buffer_info buf_info = arr.request(); + Type *ptr = static_cast(buf_info.ptr); + std::copy(ptr, ptr + ClusterSizeX * ClusterSizeY, c.data); + }); +} + template void define_cluster_vector(py::module &m, const std::string &typestr) { - auto class_name = fmt::format("ClusterVector_{}", typestr); py::class_>(m, class_name.c_str(), py::buffer_protocol()) - .def(py::init(), py::arg("cluster_size_x") = 3, - py::arg("cluster_size_y") = 3) // TODO change!!! + .def(py::init()) // TODO change!!! + /* + .def("push_back", + [](ClusterVector &self, ClusterType &cl) { + // auto view = make_view_2d(data); + self.push_back(cl); + }) + */ + /* + .def( + "push_back", + [](ClusterVector &self, py::object obj) { + ClusterType &cl = py::cast(obj); + self.push_back(cl); + }, + py::arg("cluster")) + */ + /* .def("push_back", - [](ClusterVector &self, ClusterType &cl) { - // auto view = make_view_2d(data); - self.push_back(cl); + [](ClusterVector &self, const ClusterType &cluster) { + self.push_back(cluster); }) + */ + //.def("push_back", &ClusterVector::push_back) //TODO + //implement push_back .def_property_readonly("size", &ClusterVector::size) .def("item_size", &ClusterVector::item_size) .def_property_readonly("fmt", @@ -78,7 +139,6 @@ void define_cluster_vector(py::module &m, const std::string &typestr) { template void define_cluster_finder_mt_bindings(py::module &m, const std::string &typestr) { - auto class_name = fmt::format("ClusterFinderMT_{}", typestr); py::class_>( @@ -129,7 +189,6 @@ void define_cluster_finder_mt_bindings(py::module &m, template void define_cluster_collector_bindings(py::module &m, const std::string &typestr) { - auto class_name = fmt::format("ClusterCollector_{}", typestr); py::class_>(m, class_name.c_str()) @@ -148,7 +207,6 @@ void define_cluster_collector_bindings(py::module &m, template void define_cluster_file_sink_bindings(py::module &m, const std::string &typestr) { - auto class_name = fmt::format("ClusterFileSink_{}", typestr); py::class_>(m, class_name.c_str()) @@ -159,7 +217,6 @@ void define_cluster_file_sink_bindings(py::module &m, template void define_cluster_finder_bindings(py::module &m, const std::string &typestr) { - auto class_name = fmt::format("ClusterFinder_{}", typestr); py::class_>( @@ -227,21 +284,4 @@ void define_cluster_finder_bindings(py::module &m, const std::string &typestr) { } return hitmap; }); - - py::class_(m, "DynamicCluster", py::buffer_protocol()) - .def(py::init()) - .def("size", &DynamicCluster::size) - .def("begin", &DynamicCluster::begin) - .def("end", &DynamicCluster::end) - .def_readwrite("x", &DynamicCluster::x) - .def_readwrite("y", &DynamicCluster::y) - .def_buffer([](DynamicCluster &c) -> py::buffer_info { - return py::buffer_info(c.data(), c.dt.bytes(), c.dt.format_descr(), - 1, {c.size()}, {c.dt.bytes()}); - }) - - .def("__repr__", [](const DynamicCluster &a) { - return ""; - }); } diff --git a/python/src/cluster_file.hpp b/python/src/cluster_file.hpp index 151644c..b41cab8 100644 --- a/python/src/cluster_file.hpp +++ b/python/src/cluster_file.hpp @@ -39,14 +39,6 @@ void define_cluster_file_io_bindings(py::module &m, return v; }, py::return_value_policy::take_ownership) - .def( - "read_clusters", - [](ClusterFile &self, size_t n_clusters, ROI roi) { - auto v = new ClusterVector( - self.read_clusters(n_clusters, roi)); - return v; - }, - py::return_value_policy::take_ownership) .def("read_frame", [](ClusterFile &self) { auto v = new ClusterVector(self.read_frame()); diff --git a/python/src/interpolation.hpp b/python/src/interpolation.hpp index cc14553..08ec98d 100644 --- a/python/src/interpolation.hpp +++ b/python/src/interpolation.hpp @@ -10,9 +10,9 @@ namespace py = pybind11; template -void register_interpolate(py::class_ &interpolator) { - std::string name = - fmt::format("interpolate_{}", typeid(ClusterType).name()); +void register_interpolate(py::class_ &interpolator, + const std::string &typestr) { + auto name = fmt::format("interpolate_{}", typestr); interpolator.def(name.c_str(), [](aare::Interpolator &self, @@ -50,12 +50,12 @@ void define_interpolation_bindings(py::module &m) { return return_image_data(ptr); }); - register_interpolate>(interpolator); - register_interpolate>(interpolator); - register_interpolate>(interpolator); - register_interpolate>(interpolator); - register_interpolate>(interpolator); - register_interpolate>(interpolator); + register_interpolate>(interpolator, "Cluster3x3i"); + register_interpolate>(interpolator, "Cluster3x3f"); + register_interpolate>(interpolator, "Cluster3x3d"); + register_interpolate>(interpolator, "Cluster2x2i"); + register_interpolate>(interpolator, "Cluster2x2f"); + register_interpolate>(interpolator, "Cluster2x2d"); // TODO! Evaluate without converting to double m.def( diff --git a/python/src/module.cpp b/python/src/module.cpp index 4df5d77..9d3866e 100644 --- a/python/src/module.cpp +++ b/python/src/module.cpp @@ -70,4 +70,11 @@ PYBIND11_MODULE(_aare, m) { define_cluster_collector_bindings>(m, "Cluster2x2i"); define_cluster_collector_bindings>(m, "Cluster2x2f"); define_cluster_collector_bindings>(m, "Cluster2x2d"); + + define_cluster(m, "3x3i"); + define_cluster(m, "3x3f"); + define_cluster(m, "3x3d"); + define_cluster(m, "2x2i"); + define_cluster(m, "2x2f"); + define_cluster(m, "2x2d"); } diff --git a/python/src/np_helper.hpp b/python/src/np_helper.hpp index 1845196..768efac 100644 --- a/python/src/np_helper.hpp +++ b/python/src/np_helper.hpp @@ -40,25 +40,28 @@ template py::array return_vector(std::vector *vec) { } // todo rewrite generic -template auto get_shape_3d(const py::array_t& arr) { +template +auto get_shape_3d(const py::array_t &arr) { return aare::Shape<3>{arr.shape(0), arr.shape(1), arr.shape(2)}; } -template auto make_view_3d(py::array_t& arr) { +template auto make_view_3d(py::array_t &arr) { return aare::NDView(arr.mutable_data(), get_shape_3d(arr)); } -template auto get_shape_2d(const py::array_t& arr) { +template +auto get_shape_2d(const py::array_t &arr) { return aare::Shape<2>{arr.shape(0), arr.shape(1)}; } -template auto get_shape_1d(const py::array_t& arr) { +template +auto get_shape_1d(const py::array_t &arr) { return aare::Shape<1>{arr.shape(0)}; } -template auto make_view_2d(py::array_t& arr) { +template auto make_view_2d(py::array_t &arr) { return aare::NDView(arr.mutable_data(), get_shape_2d(arr)); } -template auto make_view_1d(py::array_t& arr) { +template auto make_view_1d(py::array_t &arr) { return aare::NDView(arr.mutable_data(), get_shape_1d(arr)); } \ No newline at end of file diff --git a/python/tests/test_Cluster.py b/python/tests/test_Cluster.py new file mode 100644 index 0000000..2281e13 --- /dev/null +++ b/python/tests/test_Cluster.py @@ -0,0 +1,64 @@ +import pytest +import numpy as np + +from _aare import ClusterVector_Cluster3x3i, Interpolator, Cluster3x3i, ClusterFinder_Cluster3x3i + +def test_ClusterVector(): + """Test ClusterVector""" + + clustervector = ClusterVector_Cluster3x3i() + assert clustervector.cluster_size_x == 3 + assert clustervector.cluster_size_y == 3 + assert clustervector.item_size() == 4+9*4 + assert clustervector.frame_number == 0 + assert clustervector.capacity == 1024 + assert clustervector.size == 0 + + cluster = Cluster3x3i(0,0,np.ones(9, dtype=np.int32)) + + #clustervector.push_back(cluster) + #assert clustervector.size == 1 + + #push_back - check size + + +def test_Interpolator(): + """Test Interpolator""" + + ebins = np.linspace(0,10, 20, dtype=np.float64) + xbins = np.linspace(0, 5, 30, dtype=np.float64) + ybins = np.linspace(0, 5, 30, dtype=np.float64) + + etacube = np.zeros(shape=[30, 30, 20], dtype=np.float64) + interpolator = Interpolator(etacube, xbins, ybins, ebins) + + assert interpolator.get_ietax().shape == (30,30,20) + assert interpolator.get_ietay().shape == (30,30,20) + clustervector = ClusterVector_Cluster3x3i() + + #TODO clustervector is empty + cluster = Cluster3x3i(0,0, np.ones(9, dtype=np.int32)) + #clustervector.push_back(cluster) + num_clusters = 1; + + assert interpolator.interpolate_Cluster3x3i(clustervector).shape == (num_clusters, 3) + + +#def test_cluster_file(): + +#def test_cluster_finder(): + #"""Test ClusterFinder""" + + #clusterfinder = ClusterFinder_Cluster3x3i([100,100]) + + #clusterfinder.find_clusters() + + #clusters = clusterfinder.steal_clusters() + + #print("cluster size: ", clusters.size()) + + + + + + diff --git a/src/ClusterVector.test.cpp b/src/ClusterVector.test.cpp index c6a36d8..096abfa 100644 --- a/src/ClusterVector.test.cpp +++ b/src/ClusterVector.test.cpp @@ -61,11 +61,13 @@ TEST_CASE("Summing 3x1 clusters of int64", "[.ClusterVector]") { REQUIRE(cv.capacity() == 4); REQUIRE(cv.size() == 3); + /* auto sums = cv.sum(); REQUIRE(sums.size() == 3); REQUIRE(sums[0] == 12); REQUIRE(sums[1] == 27); REQUIRE(sums[2] == 42); + */ } TEST_CASE("Storing floats", "[.ClusterVector]") { @@ -87,10 +89,12 @@ TEST_CASE("Storing floats", "[.ClusterVector]") { REQUIRE(cv.capacity() == 10); REQUIRE(cv.size() == 2); + /* auto sums = cv.sum(); REQUIRE(sums.size() == 2); REQUIRE_THAT(sums[0], Catch::Matchers::WithinAbs(36.0, 1e-6)); REQUIRE_THAT(sums[1], Catch::Matchers::WithinAbs(76.0, 1e-6)); + */ } TEST_CASE("Push back more than initial capacity", "[.ClusterVector]") { diff --git a/src/Interpolator.cpp b/src/Interpolator.cpp index 3680522..4bc2b34 100644 --- a/src/Interpolator.cpp +++ b/src/Interpolator.cpp @@ -1,6 +1,4 @@ #include "aare/Interpolator.hpp" -#include "aare/CalculateEta.hpp" -#include "aare/algorithm.hpp" namespace aare { @@ -55,99 +53,4 @@ Interpolator::Interpolator(NDView etacube, NDView xbins, } } -// TODO: generalize to support any clustertype!!! otherwise add std::enable_if_t -// to only take Cluster2x2 and Cluster3x3 -template -std::vector -Interpolator::interpolate(const ClusterVector &clusters) { - std::vector photons; - photons.reserve(clusters.size()); - - if (clusters.cluster_size_x() == 3 || clusters.cluster_size_y() == 3) { - for (size_t i = 0; i < clusters.size(); i++) { - - auto cluster = clusters.at(i); - auto eta = calculate_eta2(cluster); - - Photon photon; - photon.x = cluster.x; - photon.y = cluster.y; - photon.energy = eta.sum; - - // auto ie = nearest_index(m_energy_bins, photon.energy)-1; - // auto ix = nearest_index(m_etabinsx, eta.x)-1; - // auto iy = nearest_index(m_etabinsy, eta.y)-1; - // Finding the index of the last element that is smaller - // should work fine as long as we have many bins - auto ie = last_smaller(m_energy_bins, photon.energy); - auto ix = last_smaller(m_etabinsx, eta.x); - auto iy = last_smaller(m_etabinsy, eta.y); - - // fmt::print("ex: {}, ix: {}, iy: {}\n", ie, ix, iy); - - double dX, dY; - int ex, ey; - // cBottomLeft = 0, - // cBottomRight = 1, - // cTopLeft = 2, - // cTopRight = 3 - switch (eta.c) { - case cTopLeft: - dX = -1.; - dY = 0; - break; - case cTopRight:; - dX = 0; - dY = 0; - break; - case cBottomLeft: - dX = -1.; - dY = -1.; - break; - case cBottomRight: - dX = 0.; - dY = -1.; - break; - } - photon.x += m_ietax(ix, iy, ie) * 2 + dX; - photon.y += m_ietay(ix, iy, ie) * 2 + dY; - photons.push_back(photon); - } - } else if (clusters.cluster_size_x() == 2 || - clusters.cluster_size_y() == 2) { - for (size_t i = 0; i < clusters.size(); i++) { - auto cluster = clusters.at(i); - auto eta = calculate_eta2(cluster); - - Photon photon; - photon.x = cluster.x; - photon.y = cluster.y; - photon.energy = eta.sum; - - // Now do some actual interpolation. - // Find which energy bin the cluster is in - // auto ie = nearest_index(m_energy_bins, photon.energy)-1; - // auto ix = nearest_index(m_etabinsx, eta.x)-1; - // auto iy = nearest_index(m_etabinsy, eta.y)-1; - // Finding the index of the last element that is smaller - // should work fine as long as we have many bins - auto ie = last_smaller(m_energy_bins, photon.energy); - auto ix = last_smaller(m_etabinsx, eta.x); - auto iy = last_smaller(m_etabinsy, eta.y); - - photon.x += m_ietax(ix, iy, ie) * - 2; // eta goes between 0 and 1 but we could move the hit - // anywhere in the 2x2 - photon.y += m_ietay(ix, iy, ie) * 2; - photons.push_back(photon); - } - - } else { - throw std::runtime_error( - "Only 3x3 and 2x2 clusters are supported for interpolation"); - } - - return photons; -} - } // namespace aare \ No newline at end of file From a12e43b1767e32453662ba56c9ee1380b9c4f02a Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Mon, 7 Apr 2025 12:27:44 +0200 Subject: [PATCH 28/51] underlying container of ClusterVcetor is now a std::vector --- include/aare/ClusterVector.hpp | 128 +++++++++++++++++++++++++++++++-- python/src/cluster.hpp | 38 +++++----- python/src/np_helper.hpp | 21 +++++- src/ClusterVector.test.cpp | 5 +- 4 files changed, 162 insertions(+), 30 deletions(-) diff --git a/include/aare/ClusterVector.hpp b/include/aare/ClusterVector.hpp index f3b55be..13ec882 100644 --- a/include/aare/ClusterVector.hpp +++ b/include/aare/ClusterVector.hpp @@ -29,6 +29,7 @@ class ClusterVector; // Forward declaration * @tparam CoordType data type of the x and y coordinates of the cluster * (normally int16_t) */ +#if 0 template class ClusterVector> { @@ -37,7 +38,7 @@ class ClusterVector> { size_t m_size{0}; size_t m_capacity; uint64_t m_frame_number{0}; // TODO! Check frame number size and type - /* + /** Format string used in the python bindings to create a numpy array from the buffer = - native byte order @@ -59,7 +60,7 @@ class ClusterVector> { */ ClusterVector(size_t capacity = 1024, uint64_t frame_number = 0) : m_capacity(capacity), m_frame_number(frame_number) { - allocate_buffer(capacity); + allocate_buffer(m_capacity); } ~ClusterVector() { delete[] m_data; } @@ -230,7 +231,7 @@ class ClusterVector> { return m_fmt_base; } - /** + /** * @brief Return the frame number of the clusters. 0 is used to indicate * that the clusters come from many frames */ @@ -240,7 +241,7 @@ class ClusterVector> { m_frame_number = frame_number; } - /** + /** * @brief Resize the vector to contain new_size clusters. If new_size is * greater than the current capacity, a new buffer is allocated. If the size * is smaller no memory is freed, size is just updated. @@ -265,5 +266,124 @@ class ClusterVector> { m_capacity = new_capacity; } }; +#endif + +/** + * @brief ClusterVector is a container for clusters of various sizes. It + * uses a contiguous memory buffer to store the clusters. It is templated on + * the data type and the coordinate type of the clusters. + * @note push_back can invalidate pointers to elements in the container + * @warning ClusterVector is currently move only to catch unintended copies, + * but this might change since there are probably use cases where copying is + * needed. + * @tparam T data type of the pixels in the cluster + * @tparam CoordType data type of the x and y coordinates of the cluster + * (normally int16_t) + */ +template +class ClusterVector> { + + std::vector> m_data{}; + uint64_t m_frame_number{0}; // TODO! Check frame number size and type + + public: + using value_type = T; + using ClusterType = Cluster; + + /** + * @brief Construct a new ClusterVector object + * @param capacity initial capacity of the buffer in number of clusters + * @param frame_number frame number of the clusters. Default is 0, which is + * also used to indicate that the clusters come from many frames + */ + ClusterVector(size_t capacity = 1024, uint64_t frame_number = 0) + : m_frame_number(frame_number) { + m_data.reserve(capacity); + } + + // Move constructor + ClusterVector(ClusterVector &&other) noexcept + : m_data(other.m_data), m_frame_number(other.m_frame_number) { + other.m_data.clear(); + } + + // Move assignment operator + ClusterVector &operator=(ClusterVector &&other) noexcept { + if (this != &other) { + m_data = other.m_data; + m_frame_number = other.m_frame_number; + other.m_data.clear(); + other.m_frame_number = 0; + } + return *this; + } + + /** + * @brief Reserve space for at least capacity clusters + * @param capacity number of clusters to reserve space for + * @note If capacity is less than the current capacity, the function does + * nothing. + */ + void reserve(size_t capacity) { m_data.reserve(capacity); } + + void resize(size_t size) { m_data.resize(size); } + + void push_back(const ClusterType &cluster) { m_data.push_back(cluster); } + + ClusterVector &operator+=(const ClusterVector &other) { + m_data.insert(m_data.end(), other.begin(), other.end()); + + return *this; + } + + /** + * @brief Return the number of clusters in the vector + */ + size_t size() const { return m_data.size(); } + + uint8_t cluster_size_x() const { return ClusterSizeX; } + + uint8_t cluster_size_y() const { return ClusterSizeY; } + + /** + * @brief Return the capacity of the buffer in number of clusters. This is + * the number of clusters that can be stored in the current buffer without + * reallocation. + */ + size_t capacity() const { return m_data.capacity(); } + + const auto begin() const { return m_data.begin(); } + + const auto end() const { return m_data.end(); } + + /** + * @brief Return the size in bytes of a single cluster + */ + size_t item_size() const { + return 2 * sizeof(CoordType) + ClusterSizeX * ClusterSizeY * sizeof(T); + } + + ClusterType *data() { return m_data.data(); } + ClusterType const *data() const { return m_data.data(); } + + /** + * @brief Return a reference to the i-th cluster casted to type V + * @tparam V type of the cluster + */ + ClusterType &at(size_t i) { return m_data[i]; } + + const ClusterType &at(size_t i) const { return m_data[i]; } + + /** + * @brief Return the frame number of the clusters. 0 is used to indicate + * that the clusters come from many frames + */ + uint64_t frame_number() const { return m_frame_number; } + + void set_frame_number(uint64_t frame_number) { + m_frame_number = frame_number; + } +}; } // namespace aare \ No newline at end of file diff --git a/python/src/cluster.hpp b/python/src/cluster.hpp index 7dcb338..b414ae1 100644 --- a/python/src/cluster.hpp +++ b/python/src/cluster.hpp @@ -58,7 +58,8 @@ void define_cluster(py::module &m, const std::string &typestr) { [](ClusterType &c, py::array_t arr) { py::buffer_info buf_info = arr.request(); Type *ptr = static_cast(buf_info.ptr); - std::copy(ptr, ptr + ClusterSizeX * ClusterSizeY, c.data); + std::copy(ptr, ptr + ClusterSizeX * ClusterSizeY, + c.data); // TODO dont iterate over centers!!! }); } @@ -68,14 +69,15 @@ void define_cluster_vector(py::module &m, const std::string &typestr) { py::class_>(m, class_name.c_str(), py::buffer_protocol()) + .def(py::init()) // TODO change!!! - /* - .def("push_back", - [](ClusterVector &self, ClusterType &cl) { - // auto view = make_view_2d(data); - self.push_back(cl); - }) - */ + /* + .def("push_back", + [](ClusterVector &self, ClusterType &cl) { + // auto view = make_view_2d(data); + self.push_back(cl); + }) + */ /* .def( "push_back", @@ -92,15 +94,11 @@ void define_cluster_vector(py::module &m, const std::string &typestr) { }) */ //.def("push_back", &ClusterVector::push_back) //TODO - //implement push_back + // implement push_back .def_property_readonly("size", &ClusterVector::size) .def("item_size", &ClusterVector::item_size) .def_property_readonly("fmt", - [typestr](ClusterVector &self) { - return fmt::format( - self.fmt_base(), self.cluster_size_x(), - self.cluster_size_y(), typestr); - }) + [typestr]() { return fmt_format; }) /* .def("sum", [](ClusterVector &self) { @@ -124,13 +122,11 @@ void define_cluster_vector(py::module &m, const std::string &typestr) { .def_buffer( [typestr](ClusterVector &self) -> py::buffer_info { return py::buffer_info( - self.data(), /* Pointer to buffer */ - self.item_size(), /* Size of one scalar */ - fmt::format(self.fmt_base(), self.cluster_size_x(), - self.cluster_size_y(), - typestr), /* Format descriptor */ - 1, /* Number of dimensions */ - {self.size()}, /* Buffer dimensions */ + self.data(), /* Pointer to buffer */ + self.item_size(), /* Size of one scalar */ + fmt_format, /* Format descriptor */ + 1, /* Number of dimensions */ + {self.size()}, /* Buffer dimensions */ {self.item_size()} /* Strides (in bytes) for each index */ ); }); diff --git a/python/src/np_helper.hpp b/python/src/np_helper.hpp index 768efac..98be52f 100644 --- a/python/src/np_helper.hpp +++ b/python/src/np_helper.hpp @@ -10,6 +10,7 @@ #include "aare/NDView.hpp" namespace py = pybind11; +using namespace aare; // Pass image data back to python as a numpy array template @@ -64,4 +65,22 @@ template auto make_view_2d(py::array_t &arr) { } template auto make_view_1d(py::array_t &arr) { return aare::NDView(arr.mutable_data(), get_shape_1d(arr)); -} \ No newline at end of file +} + +template struct fmt_format_trait; // forward declaration + +template +struct fmt_format_trait> { + + static std::string value() { + return fmt::format("T{{{}:x;{}:y;{}:data;}}", + py::format_descriptor::format(), + py::format_descriptor::format(), + fmt::format("{}{}", ClusterSizeX * ClusterSizeY, + py::format_descriptor::format())); + } +}; + +template +auto fmt_format = fmt_format_trait::value(); \ No newline at end of file diff --git a/src/ClusterVector.test.cpp b/src/ClusterVector.test.cpp index 096abfa..1880355 100644 --- a/src/ClusterVector.test.cpp +++ b/src/ClusterVector.test.cpp @@ -25,10 +25,7 @@ TEST_CASE("ClusterVector 2x2 int32_t capacity 4, push back then read", REQUIRE(cv.size() == 1); REQUIRE(cv.capacity() == 4); - // Read the cluster back out using copy. TODO! Can we improve the API? - Cluster c2; - std::byte *ptr = cv.element_ptr(0); - std::copy(ptr, ptr + cv.item_size(), reinterpret_cast(&c2)); + auto c2 = cv.at(0); // Check that the data is the same REQUIRE(c1.x == c2.x); From 017960d963073634b7bc1cf8317d31962020e058 Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Mon, 7 Apr 2025 13:41:14 +0200 Subject: [PATCH 29/51] added push_back property --- python/src/cluster.hpp | 4 ++-- python/tests/test_Cluster.py | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/python/src/cluster.hpp b/python/src/cluster.hpp index b414ae1..fda80a7 100644 --- a/python/src/cluster.hpp +++ b/python/src/cluster.hpp @@ -87,12 +87,12 @@ void define_cluster_vector(py::module &m, const std::string &typestr) { }, py::arg("cluster")) */ - /* + .def("push_back", [](ClusterVector &self, const ClusterType &cluster) { self.push_back(cluster); }) - */ + //.def("push_back", &ClusterVector::push_back) //TODO // implement push_back .def_property_readonly("size", &ClusterVector::size) diff --git a/python/tests/test_Cluster.py b/python/tests/test_Cluster.py index 2281e13..bd2c482 100644 --- a/python/tests/test_Cluster.py +++ b/python/tests/test_Cluster.py @@ -16,12 +16,13 @@ def test_ClusterVector(): cluster = Cluster3x3i(0,0,np.ones(9, dtype=np.int32)) - #clustervector.push_back(cluster) - #assert clustervector.size == 1 + clustervector.push_back(cluster) + assert clustervector.size == 1 #push_back - check size + def test_Interpolator(): """Test Interpolator""" @@ -36,12 +37,11 @@ def test_Interpolator(): assert interpolator.get_ietay().shape == (30,30,20) clustervector = ClusterVector_Cluster3x3i() - #TODO clustervector is empty cluster = Cluster3x3i(0,0, np.ones(9, dtype=np.int32)) #clustervector.push_back(cluster) - num_clusters = 1; + #num_clusters = 1; - assert interpolator.interpolate_Cluster3x3i(clustervector).shape == (num_clusters, 3) + #assert interpolator.interpolate_Cluster3x3i(clustervector).shape == (num_clusters, 3) #def test_cluster_file(): From 10e4e10431884af9a9f9abdd9084fcebba54247f Mon Sep 17 00:00:00 2001 From: froejdh_e Date: Mon, 7 Apr 2025 15:33:37 +0200 Subject: [PATCH 30/51] function signature for push back --- python/aare/__init__.py | 8 ++++---- python/src/cluster.hpp | 5 ++++- python/src/module.cpp | 12 ++++++------ 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/python/aare/__init__.py b/python/aare/__init__.py index 058d7cf..c9076cf 100644 --- a/python/aare/__init__.py +++ b/python/aare/__init__.py @@ -2,14 +2,14 @@ from . import _aare -from ._aare import File, RawMasterFile, RawSubFile -from ._aare import Pedestal_d, Pedestal_f, ClusterFinder, VarClusterFinder +# from ._aare import File, RawMasterFile, RawSubFile +# from ._aare import Pedestal_d, Pedestal_f, ClusterFinder, VarClusterFinder from ._aare import DetectorType -from ._aare import ClusterFile +from ._aare import ClusterFile_Cluster3x3i as ClusterFile from ._aare import hitmap from ._aare import ROI -from ._aare import ClusterFinderMT, ClusterCollector, ClusterFileSink, ClusterVector_i +# from ._aare import ClusterFinderMT, ClusterCollector, ClusterFileSink, ClusterVector_i from ._aare import fit_gaus, fit_pol1 from ._aare import Interpolator diff --git a/python/src/cluster.hpp b/python/src/cluster.hpp index fda80a7..30b80f0 100644 --- a/python/src/cluster.hpp +++ b/python/src/cluster.hpp @@ -63,8 +63,11 @@ void define_cluster(py::module &m, const std::string &typestr) { }); } -template +template void define_cluster_vector(py::module &m, const std::string &typestr) { + using ClusterType = + Cluster; auto class_name = fmt::format("ClusterVector_{}", typestr); py::class_>(m, class_name.c_str(), diff --git a/python/src/module.cpp b/python/src/module.cpp index 9d3866e..38d3681 100644 --- a/python/src/module.cpp +++ b/python/src/module.cpp @@ -36,12 +36,12 @@ PYBIND11_MODULE(_aare, m) { define_cluster_file_io_bindings>(m, "Cluster2x2f"); define_cluster_file_io_bindings>(m, "Cluster2x2d"); - define_cluster_vector>(m, "Cluster3x3i"); - define_cluster_vector>(m, "Cluster3x3d"); - define_cluster_vector>(m, "Cluster3x3f"); - define_cluster_vector>(m, "Cluster2x2i"); - define_cluster_vector>(m, "Cluster2x2d"); - define_cluster_vector>(m, "Cluster2x2f"); + define_cluster_vector(m, "Cluster3x3i"); + define_cluster_vector(m, "Cluster3x3d"); + define_cluster_vector(m, "Cluster3x3f"); + define_cluster_vector(m, "Cluster2x2i"); + define_cluster_vector(m, "Cluster2x2d"); + define_cluster_vector(m, "Cluster2x2f"); define_cluster_finder_bindings>(m, "Cluster3x3i"); define_cluster_finder_bindings>(m, "Cluster3x3d"); From a13affa4d3a3ccb52c16b0259311d4433d7001f9 Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Thu, 10 Apr 2025 09:13:58 +0200 Subject: [PATCH 31/51] changed template arguments added tests --- python/src/cluster.hpp | 116 +++++++++++++++-------------------- python/src/cluster_file.hpp | 5 ++ python/src/interpolation.hpp | 23 +++---- python/src/module.cpp | 55 +++++++++-------- python/tests/test_Cluster.py | 96 +++++++++++++++++++++++------ 5 files changed, 175 insertions(+), 120 deletions(-) diff --git a/python/src/cluster.hpp b/python/src/cluster.hpp index 30b80f0..f6d3636 100644 --- a/python/src/cluster.hpp +++ b/python/src/cluster.hpp @@ -23,10 +23,8 @@ template ; py::class_>( - m, class_name.c_str()) + m, class_name.c_str(), py::buffer_protocol()) .def(py::init([](uint8_t x, uint8_t y, py::array_t data) { py::buffer_info buf_info = data.request(); @@ -37,83 +35,57 @@ void define_cluster(py::module &m, const std::string &typestr) { std::copy(ptr, ptr + ClusterSizeX * ClusterSizeY, cluster.data); // Copy array contents return cluster; - })) + })); - //.def(py::init<>()) - .def_readwrite("x", &ClusterType::x) - .def_readwrite("y", &ClusterType::y) - .def_property( - "data", - [](ClusterType &c) -> py::array { - return py::array(py::buffer_info( - c.data, sizeof(Type), - py::format_descriptor::format(), // Type - // format - 1, // Number of dimensions - {static_cast(ClusterSizeX * - ClusterSizeY)}, // Shape (flattened) - {sizeof(Type)} // Stride (step size between elements) - )); - }, - [](ClusterType &c, py::array_t arr) { - py::buffer_info buf_info = arr.request(); - Type *ptr = static_cast(buf_info.ptr); - std::copy(ptr, ptr + ClusterSizeX * ClusterSizeY, - c.data); // TODO dont iterate over centers!!! - }); + /* + .def_property( + "data", + [](ClusterType &c) -> py::array { + return py::array(py::buffer_info( + c.data, sizeof(Type), + py::format_descriptor::format(), // Type + // format + 1, // Number of dimensions + {static_cast(ClusterSizeX * + ClusterSizeY)}, // Shape (flattened) + {sizeof(Type)} // Stride (step size between elements) + )); + }, + [](ClusterType &c, py::array_t arr) { + py::buffer_info buf_info = arr.request(); + Type *ptr = static_cast(buf_info.ptr); + std::copy(ptr, ptr + ClusterSizeX * ClusterSizeY, + c.data); // TODO dont iterate over centers!!! + + }); + */ } template void define_cluster_vector(py::module &m, const std::string &typestr) { using ClusterType = - Cluster; + Cluster; auto class_name = fmt::format("ClusterVector_{}", typestr); - py::class_>(m, class_name.c_str(), - py::buffer_protocol()) + py::class_, void>>( + m, class_name.c_str(), + py::buffer_protocol()) .def(py::init()) // TODO change!!! - /* - .def("push_back", - [](ClusterVector &self, ClusterType &cl) { - // auto view = make_view_2d(data); - self.push_back(cl); - }) - */ - /* - .def( - "push_back", - [](ClusterVector &self, py::object obj) { - ClusterType &cl = py::cast(obj); - self.push_back(cl); - }, - py::arg("cluster")) - */ .def("push_back", [](ClusterVector &self, const ClusterType &cluster) { self.push_back(cluster); }) - //.def("push_back", &ClusterVector::push_back) //TODO // implement push_back .def_property_readonly("size", &ClusterVector::size) .def("item_size", &ClusterVector::item_size) .def_property_readonly("fmt", [typestr]() { return fmt_format; }) - /* - .def("sum", - [](ClusterVector &self) { - auto *vec = new std::vector(self.sum()); - return return_vector(vec); - }) - .def("sum_2x2", - [](ClusterVector &self) { - auto *vec = new std::vector(self.sum_2x2()); - return return_vector(vec); - }) - */ + .def_property_readonly("cluster_size_x", &ClusterVector::cluster_size_x) .def_property_readonly("cluster_size_y", @@ -135,11 +107,14 @@ void define_cluster_vector(py::module &m, const std::string &typestr) { }); } -template +template void define_cluster_finder_mt_bindings(py::module &m, const std::string &typestr) { auto class_name = fmt::format("ClusterFinderMT_{}", typestr); + using ClusterType = Cluster; + py::class_>( m, class_name.c_str()) .def(py::init, pd_type, size_t, size_t>(), @@ -185,11 +160,14 @@ void define_cluster_finder_mt_bindings(py::module &m, py::arg("thread_index") = 0); } -template +template void define_cluster_collector_bindings(py::module &m, const std::string &typestr) { auto class_name = fmt::format("ClusterCollector_{}", typestr); + using ClusterType = Cluster; + py::class_>(m, class_name.c_str()) .def(py::init *>()) .def("stop", &ClusterCollector::stop) @@ -198,26 +176,32 @@ void define_cluster_collector_bindings(py::module &m, [](ClusterCollector &self) { auto v = new std::vector>( self.steal_clusters()); - return v; + return v; // TODO change!!! }, py::return_value_policy::take_ownership); } -template +template void define_cluster_file_sink_bindings(py::module &m, const std::string &typestr) { auto class_name = fmt::format("ClusterFileSink_{}", typestr); + using ClusterType = Cluster; + py::class_>(m, class_name.c_str()) .def(py::init *, const std::filesystem::path &>()) .def("stop", &ClusterFileSink::stop); } -template +template void define_cluster_finder_bindings(py::module &m, const std::string &typestr) { auto class_name = fmt::format("ClusterFinder_{}", typestr); + using ClusterType = Cluster; + py::class_>( m, class_name.c_str()) .def(py::init, pd_type, size_t>(), py::arg("image_size"), @@ -248,9 +232,9 @@ void define_cluster_finder_bindings(py::module &m, const std::string &typestr) { "steal_clusters", [](ClusterFinder &self, bool realloc_same_capacity) { - auto v = new ClusterVector( - self.steal_clusters(realloc_same_capacity)); - return v; + ClusterVector clusters = + self.steal_clusters(realloc_same_capacity); + return clusters; }, py::arg("realloc_same_capacity") = false) .def( diff --git a/python/src/cluster_file.hpp b/python/src/cluster_file.hpp index b41cab8..7ece8e6 100644 --- a/python/src/cluster_file.hpp +++ b/python/src/cluster_file.hpp @@ -80,7 +80,12 @@ void define_cluster_file_io_bindings(py::module &m, } return v; }); +} +template +void register_calculate_eta(py::module &m) { + using ClusterType = Cluster; m.def("calculate_eta2", [](const aare::ClusterVector &clusters) { auto eta2 = new NDArray(calculate_eta2(clusters)); diff --git a/python/src/interpolation.hpp b/python/src/interpolation.hpp index 08ec98d..e667015 100644 --- a/python/src/interpolation.hpp +++ b/python/src/interpolation.hpp @@ -9,12 +9,13 @@ namespace py = pybind11; -template -void register_interpolate(py::class_ &interpolator, - const std::string &typestr) { - auto name = fmt::format("interpolate_{}", typestr); +template +void register_interpolate(py::class_ &interpolator) { - interpolator.def(name.c_str(), + using ClusterType = Cluster; + + interpolator.def("interpolate", [](aare::Interpolator &self, const ClusterVector &clusters) { auto photons = self.interpolate(clusters); @@ -50,12 +51,12 @@ void define_interpolation_bindings(py::module &m) { return return_image_data(ptr); }); - register_interpolate>(interpolator, "Cluster3x3i"); - register_interpolate>(interpolator, "Cluster3x3f"); - register_interpolate>(interpolator, "Cluster3x3d"); - register_interpolate>(interpolator, "Cluster2x2i"); - register_interpolate>(interpolator, "Cluster2x2f"); - register_interpolate>(interpolator, "Cluster2x2d"); + register_interpolate(interpolator); + register_interpolate(interpolator); + register_interpolate(interpolator); + register_interpolate(interpolator); + register_interpolate(interpolator); + register_interpolate(interpolator); // TODO! Evaluate without converting to double m.def( diff --git a/python/src/module.cpp b/python/src/module.cpp index 38d3681..bfc1bc1 100644 --- a/python/src/module.cpp +++ b/python/src/module.cpp @@ -43,33 +43,33 @@ PYBIND11_MODULE(_aare, m) { define_cluster_vector(m, "Cluster2x2d"); define_cluster_vector(m, "Cluster2x2f"); - define_cluster_finder_bindings>(m, "Cluster3x3i"); - define_cluster_finder_bindings>(m, "Cluster3x3d"); - define_cluster_finder_bindings>(m, "Cluster3x3f"); - define_cluster_finder_bindings>(m, "Cluster2x2i"); - define_cluster_finder_bindings>(m, "Cluster2x2d"); - define_cluster_finder_bindings>(m, "Cluster2x2f"); + define_cluster_finder_bindings(m, "Cluster3x3i"); + define_cluster_finder_bindings(m, "Cluster3x3d"); + define_cluster_finder_bindings(m, "Cluster3x3f"); + define_cluster_finder_bindings(m, "Cluster2x2i"); + define_cluster_finder_bindings(m, "Cluster2x2d"); + define_cluster_finder_bindings(m, "Cluster2x2f"); - define_cluster_finder_mt_bindings>(m, "Cluster3x3i"); - define_cluster_finder_mt_bindings>(m, "Cluster3x3d"); - define_cluster_finder_mt_bindings>(m, "Cluster3x3f"); - define_cluster_finder_mt_bindings>(m, "Cluster2x2i"); - define_cluster_finder_mt_bindings>(m, "Cluster2x2d"); - define_cluster_finder_mt_bindings>(m, "Cluster2x2f"); + define_cluster_finder_mt_bindings(m, "Cluster3x3i"); + define_cluster_finder_mt_bindings(m, "Cluster3x3d"); + define_cluster_finder_mt_bindings(m, "Cluster3x3f"); + define_cluster_finder_mt_bindings(m, "Cluster2x2i"); + define_cluster_finder_mt_bindings(m, "Cluster2x2d"); + define_cluster_finder_mt_bindings(m, "Cluster2x2f"); - define_cluster_file_sink_bindings>(m, "Cluster3x3i"); - define_cluster_file_sink_bindings>(m, "Cluster3x3d"); - define_cluster_file_sink_bindings>(m, "Cluster3x3f"); - define_cluster_file_sink_bindings>(m, "Cluster2x2i"); - define_cluster_file_sink_bindings>(m, "Cluster2x2d"); - define_cluster_file_sink_bindings>(m, "Cluster2x2f"); + define_cluster_file_sink_bindings(m, "Cluster3x3i"); + define_cluster_file_sink_bindings(m, "Cluster3x3d"); + define_cluster_file_sink_bindings(m, "Cluster3x3f"); + define_cluster_file_sink_bindings(m, "Cluster2x2i"); + define_cluster_file_sink_bindings(m, "Cluster2x2d"); + define_cluster_file_sink_bindings(m, "Cluster2x2f"); - define_cluster_collector_bindings>(m, "Cluster3x3i"); - define_cluster_collector_bindings>(m, "Cluster3x3f"); - define_cluster_collector_bindings>(m, "Cluster3x3d"); - define_cluster_collector_bindings>(m, "Cluster2x2i"); - define_cluster_collector_bindings>(m, "Cluster2x2f"); - define_cluster_collector_bindings>(m, "Cluster2x2d"); + define_cluster_collector_bindings(m, "Cluster3x3i"); + define_cluster_collector_bindings(m, "Cluster3x3f"); + define_cluster_collector_bindings(m, "Cluster3x3d"); + define_cluster_collector_bindings(m, "Cluster2x2i"); + define_cluster_collector_bindings(m, "Cluster2x2f"); + define_cluster_collector_bindings(m, "Cluster2x2d"); define_cluster(m, "3x3i"); define_cluster(m, "3x3f"); @@ -77,4 +77,11 @@ PYBIND11_MODULE(_aare, m) { define_cluster(m, "2x2i"); define_cluster(m, "2x2f"); define_cluster(m, "2x2d"); + + register_calculate_eta(m); + register_calculate_eta(m); + register_calculate_eta(m); + register_calculate_eta(m); + register_calculate_eta(m); + register_calculate_eta(m); } diff --git a/python/tests/test_Cluster.py b/python/tests/test_Cluster.py index bd2c482..3bb4828 100644 --- a/python/tests/test_Cluster.py +++ b/python/tests/test_Cluster.py @@ -1,12 +1,12 @@ import pytest import numpy as np -from _aare import ClusterVector_Cluster3x3i, Interpolator, Cluster3x3i, ClusterFinder_Cluster3x3i +import aare._aare as aare #import ClusterVector_Cluster3x3i, ClusterVector_Cluster2x2i, Interpolator, Cluster3x3i, ClusterFinder_Cluster3x3i, Cluster2x2i, ClusterFile_Cluster3x3i, Cluster3x3f, calculate_eta2 def test_ClusterVector(): """Test ClusterVector""" - clustervector = ClusterVector_Cluster3x3i() + clustervector = aare.ClusterVector_Cluster3x3i() assert clustervector.cluster_size_x == 3 assert clustervector.cluster_size_y == 3 assert clustervector.item_size() == 4+9*4 @@ -14,14 +14,16 @@ def test_ClusterVector(): assert clustervector.capacity == 1024 assert clustervector.size == 0 - cluster = Cluster3x3i(0,0,np.ones(9, dtype=np.int32)) + cluster = aare.Cluster3x3i(0,0,np.ones(9, dtype=np.int32)) clustervector.push_back(cluster) assert clustervector.size == 1 - #push_back - check size - + with pytest.raises(TypeError): # Or use the appropriate exception type + clustervector.push_back(aare.Cluster2x2i(0,0,np.ones(4, dtype=np.int32))) + with pytest.raises(TypeError): + clustervector.push_back(aare.Cluster3x3f(0,0,np.ones(9, dtype=np.float32))) def test_Interpolator(): """Test Interpolator""" @@ -31,31 +33,87 @@ def test_Interpolator(): ybins = np.linspace(0, 5, 30, dtype=np.float64) etacube = np.zeros(shape=[30, 30, 20], dtype=np.float64) - interpolator = Interpolator(etacube, xbins, ybins, ebins) + interpolator = aare.Interpolator(etacube, xbins, ybins, ebins) assert interpolator.get_ietax().shape == (30,30,20) assert interpolator.get_ietay().shape == (30,30,20) - clustervector = ClusterVector_Cluster3x3i() + clustervector = aare.ClusterVector_Cluster3x3i() - cluster = Cluster3x3i(0,0, np.ones(9, dtype=np.int32)) - #clustervector.push_back(cluster) - #num_clusters = 1; + cluster = aare.Cluster3x3i(0,0, np.ones(9, dtype=np.int32)) + clustervector.push_back(cluster) - #assert interpolator.interpolate_Cluster3x3i(clustervector).shape == (num_clusters, 3) + interpolated_photons = interpolator.interpolate(clustervector) + + assert interpolated_photons.size == 1 + + assert interpolated_photons[0]["x"] == -1 + assert interpolated_photons[0]["y"] == -1 + assert interpolated_photons[0]["energy"] == 4 #eta_sum = 4, dx, dy = -1,-1 m_ietax = 0, m_ietay = 0 + + clustervector = aare.ClusterVector_Cluster2x2i() + + cluster = aare.Cluster2x2i(0,0, np.ones(4, dtype=np.int32)) + clustervector.push_back(cluster) + + interpolated_photons = interpolator.interpolate(clustervector) + + assert interpolated_photons.size == 1 + + assert interpolated_photons[0]["x"] == 0 + assert interpolated_photons[0]["y"] == 0 + assert interpolated_photons[0]["energy"] == 4 + +@pytest.mark.files +def test_cluster_file(): + """Test ClusterFile""" + cluster_file = aare.ClusterFile_Cluster3x3i(test_data_path() / "clust/single_frame_97_clustrers.clust") + clustervector = cluster_file.read_clusters() #conversion does not work + + cluster_file.close() + + ###reading with wrong file + cluster_file = ClusterFile_Cluster2x2i(test_data_path() / "clust/single_frame_97_clustrers.clust") #TODO check behavior! + +def test_calculate_eta(): + """Calculate Eta""" + clusters = aare.ClusterVector_Cluster3x3i() + clusters.push_back(aare.Cluster3x3i(0,0, np.ones(9, dtype=np.int32))) + clusters.push_back(aare.Cluster3x3i(0,0, np.array([1,1,1,2,2,2,3,3,3]))) + + eta2 = aare.calculate_eta2(clusters) + + assert eta2.shape == (2,2) + assert eta2[0,0] == 0.5 + assert eta2[0,1] == 0.5 + assert eta2[1,0] == 0.5 + assert eta2[1,1] == 0.6 #1/5 + +def test_cluster_finder(): + """Test ClusterFinder""" + + clusterfinder = aare.ClusterFinder_Cluster3x3i([100,100]) + + #frame = np.random.rand(100,100) + frame = np.zeros(shape=[100,100]) + + clusterfinder.find_clusters(frame) + + clusters = clusterfinder.steal_clusters(False) #conversion does not work + + assert clusters.size == 0 -#def test_cluster_file(): +def test_cluster_collector(): + """Test ClusterCollector""" -#def test_cluster_finder(): - #"""Test ClusterFinder""" + clusterfinder = aare.ClusterFinderMT_Cluster3x3i([100,100]) #TODO: no idea what the data is in InputQueue not zero - #clusterfinder = ClusterFinder_Cluster3x3i([100,100]) + clustercollector = aare.ClusterCollector_Cluster3x3i(clusterfinder) - #clusterfinder.find_clusters() + cluster_vectors = clustercollector.steal_clusters() - #clusters = clusterfinder.steal_clusters() - - #print("cluster size: ", clusters.size()) + assert len(cluster_vectors) == 1 #single thread execution + assert cluster_vectors[0].size == 0 # From 53a90e197e2c4c468fbb6e8f84d678cc144f2a0e Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Thu, 10 Apr 2025 10:41:58 +0200 Subject: [PATCH 32/51] added additional tests --- include/aare/ClusterFile.hpp | 41 ---- python/aare/__init__.py | 2 +- python/src/cluster_file.hpp | 7 +- python/src/module.cpp | 12 +- python/tests/conftest.py | 7 +- python/tests/test_Cluster.py | 17 +- src/ClusterFile.cpp | 396 ----------------------------------- src/Interpolator.cpp | 86 -------- 8 files changed, 29 insertions(+), 539 deletions(-) delete mode 100644 src/ClusterFile.cpp diff --git a/include/aare/ClusterFile.hpp b/include/aare/ClusterFile.hpp index 1995a16..ff5d338 100644 --- a/include/aare/ClusterFile.hpp +++ b/include/aare/ClusterFile.hpp @@ -11,7 +11,6 @@ namespace aare { -<<<<<<< HEAD /* Binary cluster file. Expects data to be layed out as: int32_t frame_number @@ -21,44 +20,6 @@ int32_t frame_number uint32_t number_of_clusters .... */ -======= - -// TODO! Legacy enums, migrate to enum class -typedef enum { - cBottomLeft = 0, - cBottomRight = 1, - cTopLeft = 2, - cTopRight = 3 -} corner; - -typedef enum { - pBottomLeft = 0, - pBottom = 1, - pBottomRight = 2, - pLeft = 3, - pCenter = 4, - pRight = 5, - pTopLeft = 6, - pTop = 7, - pTopRight = 8 -} pixel; - -struct Eta2 { - double x; - double y; - corner c; - int32_t sum; -}; - -struct ClusterAnalysis { - uint32_t c; - int32_t tot; - double etax; - double etay; -}; - - ->>>>>>> developer // TODO: change to support any type of clusters, e.g. header line with // clsuter_size_x, cluster_size_y, @@ -109,8 +70,6 @@ class ClusterFile { */ ClusterVector read_clusters(size_t n_clusters); - ClusterVector read_clusters(size_t n_clusters, ROI roi); - /** * @brief Read a single frame from the file and return the clusters. The * cluster vector will have the frame number set. diff --git a/python/aare/__init__.py b/python/aare/__init__.py index 36aac14..8c51d73 100644 --- a/python/aare/__init__.py +++ b/python/aare/__init__.py @@ -3,7 +3,7 @@ from . import _aare from ._aare import File, RawMasterFile, RawSubFile, JungfrauDataFile -from ._aare import Pedestal_d, Pedestal_f, ClusterFinder, VarClusterFinder +from ._aare import Pedestal_d, Pedestal_f, ClusterFinder_Cluster3x3i, VarClusterFinder from ._aare import DetectorType from ._aare import ClusterFile_Cluster3x3i as ClusterFile from ._aare import hitmap diff --git a/python/src/cluster_file.hpp b/python/src/cluster_file.hpp index 7ece8e6..3e7aa48 100644 --- a/python/src/cluster_file.hpp +++ b/python/src/cluster_file.hpp @@ -19,11 +19,12 @@ namespace py = pybind11; using namespace ::aare; -template +template void define_cluster_file_io_bindings(py::module &m, const std::string &typestr) { - // PYBIND11_NUMPY_DTYPE(Cluster, x, y, - // data); // is this used - maybe use as cluster type + + using ClusterType = Cluster; auto class_name = fmt::format("ClusterFile_{}", typestr); diff --git a/python/src/module.cpp b/python/src/module.cpp index 78fd283..8d5b5ab 100644 --- a/python/src/module.cpp +++ b/python/src/module.cpp @@ -32,12 +32,12 @@ PYBIND11_MODULE(_aare, m) { define_interpolation_bindings(m); define_jungfrau_data_file_io_bindings(m); - define_cluster_file_io_bindings>(m, "Cluster3x3i"); - define_cluster_file_io_bindings>(m, "Cluster3x3d"); - define_cluster_file_io_bindings>(m, "Cluster3x3f"); - define_cluster_file_io_bindings>(m, "Cluster2x2i"); - define_cluster_file_io_bindings>(m, "Cluster2x2f"); - define_cluster_file_io_bindings>(m, "Cluster2x2d"); + define_cluster_file_io_bindings(m, "Cluster3x3i"); + define_cluster_file_io_bindings(m, "Cluster3x3d"); + define_cluster_file_io_bindings(m, "Cluster3x3f"); + define_cluster_file_io_bindings(m, "Cluster2x2i"); + define_cluster_file_io_bindings(m, "Cluster2x2f"); + define_cluster_file_io_bindings(m, "Cluster2x2d"); define_cluster_vector(m, "Cluster3x3i"); define_cluster_vector(m, "Cluster3x3d"); diff --git a/python/tests/conftest.py b/python/tests/conftest.py index 5badf13..fbcfeb3 100644 --- a/python/tests/conftest.py +++ b/python/tests/conftest.py @@ -25,5 +25,10 @@ def pytest_collection_modifyitems(config, items): @pytest.fixture def test_data_path(): - return Path(os.environ["AARE_TEST_DATA"]) + env_value = os.environ.get("AARE_TEST_DATA") + if not env_value: + raise RuntimeError("Environment variable AARE_TEST_DATA is not set or is empty") + + return Path(env_value) + diff --git a/python/tests/test_Cluster.py b/python/tests/test_Cluster.py index 3bb4828..29d5ad9 100644 --- a/python/tests/test_Cluster.py +++ b/python/tests/test_Cluster.py @@ -1,7 +1,9 @@ import pytest import numpy as np -import aare._aare as aare #import ClusterVector_Cluster3x3i, ClusterVector_Cluster2x2i, Interpolator, Cluster3x3i, ClusterFinder_Cluster3x3i, Cluster2x2i, ClusterFile_Cluster3x3i, Cluster3x3f, calculate_eta2 +import aare._aare as aare +from conftest import test_data_path + def test_ClusterVector(): """Test ClusterVector""" @@ -64,15 +66,19 @@ def test_Interpolator(): assert interpolated_photons[0]["energy"] == 4 @pytest.mark.files -def test_cluster_file(): +def test_cluster_file(test_data_path): """Test ClusterFile""" - cluster_file = aare.ClusterFile_Cluster3x3i(test_data_path() / "clust/single_frame_97_clustrers.clust") - clustervector = cluster_file.read_clusters() #conversion does not work + cluster_file = aare.ClusterFile_Cluster3x3i(test_data_path / "clust/single_frame_97_clustrers.clust") + clustervector = cluster_file.read_clusters(10) #conversion does not work cluster_file.close() + assert clustervector.size == 10 + ###reading with wrong file - cluster_file = ClusterFile_Cluster2x2i(test_data_path() / "clust/single_frame_97_clustrers.clust") #TODO check behavior! + with pytest.raises(TypeError): + cluster_file = aare.ClusterFile_Cluster2x2i(test_data_path / "clust/single_frame_97_clustrers.clust") + cluster_file.close() def test_calculate_eta(): """Calculate Eta""" @@ -103,6 +109,7 @@ def test_cluster_finder(): assert clusters.size == 0 +#TODO dont understand behavior def test_cluster_collector(): """Test ClusterCollector""" diff --git a/src/ClusterFile.cpp b/src/ClusterFile.cpp deleted file mode 100644 index f77ac92..0000000 --- a/src/ClusterFile.cpp +++ /dev/null @@ -1,396 +0,0 @@ -#include "aare/ClusterFile.hpp" - -#include - -namespace aare { - -ClusterFile::ClusterFile(const std::filesystem::path &fname, size_t chunk_size, - const std::string &mode) - : m_chunk_size(chunk_size), m_mode(mode) { - - if (mode == "r") { - fp = fopen(fname.c_str(), "rb"); - if (!fp) { - throw std::runtime_error("Could not open file for reading: " + - fname.string()); - } - } else if (mode == "w") { - fp = fopen(fname.c_str(), "wb"); - if (!fp) { - throw std::runtime_error("Could not open file for writing: " + - fname.string()); - } - } else if (mode == "a") { - fp = fopen(fname.c_str(), "ab"); - if (!fp) { - throw std::runtime_error("Could not open file for appending: " + - fname.string()); - } - } else { - throw std::runtime_error("Unsupported mode: " + mode); - } -} - -void ClusterFile::set_roi(ROI roi){ - m_roi = roi; -} - -void ClusterFile::set_noise_map(const NDView noise_map){ - m_noise_map = NDArray(noise_map); -} - -void ClusterFile::set_gain_map(const NDView gain_map){ - m_gain_map = NDArray(gain_map); -} - -ClusterFile::~ClusterFile() { close(); } - -void ClusterFile::close() { - if (fp) { - fclose(fp); - fp = nullptr; - } -} - -void ClusterFile::write_frame(const ClusterVector &clusters) { - if (m_mode != "w" && m_mode != "a") { - throw std::runtime_error("File not opened for writing"); - } - if (!(clusters.cluster_size_x() == 3) && - !(clusters.cluster_size_y() == 3)) { - throw std::runtime_error("Only 3x3 clusters are supported"); - } - //First write the frame number - 4 bytes - int32_t frame_number = clusters.frame_number(); - if(fwrite(&frame_number, sizeof(frame_number), 1, fp)!=1){ - throw std::runtime_error(LOCATION + "Could not write frame number"); - } - - //Then write the number of clusters - 4 bytes - uint32_t n_clusters = clusters.size(); - if(fwrite(&n_clusters, sizeof(n_clusters), 1, fp)!=1){ - throw std::runtime_error(LOCATION + "Could not write number of clusters"); - } - - //Now write the clusters in the frame - if(fwrite(clusters.data(), clusters.item_size(), clusters.size(), fp)!=clusters.size()){ - throw std::runtime_error(LOCATION + "Could not write clusters"); - } -} - - -ClusterVector ClusterFile::read_clusters(size_t n_clusters){ - if (m_mode != "r") { - throw std::runtime_error("File not opened for reading"); - } - if (m_noise_map || m_roi){ - return read_clusters_with_cut(n_clusters); - }else{ - return read_clusters_without_cut(n_clusters); - } -} - -ClusterVector ClusterFile::read_clusters_without_cut(size_t n_clusters) { - if (m_mode != "r") { - throw std::runtime_error("File not opened for reading"); - } - - ClusterVector clusters(3,3, n_clusters); - - int32_t iframe = 0; // frame number needs to be 4 bytes! - size_t nph_read = 0; - uint32_t nn = m_num_left; - uint32_t nph = m_num_left; // number of clusters in frame needs to be 4 - - // auto buf = reinterpret_cast(clusters.data()); - auto buf = clusters.data(); - // if there are photons left from previous frame read them first - if (nph) { - if (nph > n_clusters) { - // if we have more photons left in the frame then photons to read we - // read directly the requested number - nn = n_clusters; - } else { - nn = nph; - } - nph_read += fread((buf + nph_read*clusters.item_size()), - clusters.item_size(), nn, fp); - m_num_left = nph - nn; // write back the number of photons left - } - - if (nph_read < n_clusters) { - // keep on reading frames and photons until reaching n_clusters - while (fread(&iframe, sizeof(iframe), 1, fp)) { - clusters.set_frame_number(iframe); - // read number of clusters in frame - if (fread(&nph, sizeof(nph), 1, fp)) { - if (nph > (n_clusters - nph_read)) - nn = n_clusters - nph_read; - else - nn = nph; - - nph_read += fread((buf + nph_read*clusters.item_size()), - clusters.item_size(), nn, fp); - m_num_left = nph - nn; - } - if (nph_read >= n_clusters) - break; - } - } - - // Resize the vector to the number of clusters. - // No new allocation, only change bounds. - clusters.resize(nph_read); - if(m_gain_map) - clusters.apply_gain_map(m_gain_map->view()); - return clusters; -} - - -ClusterVector ClusterFile::read_clusters_with_cut(size_t n_clusters) { - ClusterVector clusters(3,3); - clusters.reserve(n_clusters); - - // if there are photons left from previous frame read them first - if (m_num_left) { - while(m_num_left && clusters.size() < n_clusters){ - Cluster3x3 c = read_one_cluster(); - if(is_selected(c)){ - clusters.push_back(c.x, c.y, reinterpret_cast(c.data)); - } - } - } - - // we did not have enough clusters left in the previous frame - // keep on reading frames until reaching n_clusters - if (clusters.size() < n_clusters) { - // sanity check - if (m_num_left) { - throw std::runtime_error(LOCATION + "Entered second loop with clusters left\n"); - } - - int32_t frame_number = 0; // frame number needs to be 4 bytes! - while (fread(&frame_number, sizeof(frame_number), 1, fp)) { - if (fread(&m_num_left, sizeof(m_num_left), 1, fp)) { - clusters.set_frame_number(frame_number); //cluster vector will hold the last frame number - while(m_num_left && clusters.size() < n_clusters){ - Cluster3x3 c = read_one_cluster(); - if(is_selected(c)){ - clusters.push_back(c.x, c.y, reinterpret_cast(c.data)); - } - } - } - - // we have enough clusters, break out of the outer while loop - if (clusters.size() >= n_clusters) - break; - } - - } - if(m_gain_map) - clusters.apply_gain_map(m_gain_map->view()); - - return clusters; -} - -Cluster3x3 ClusterFile::read_one_cluster(){ - Cluster3x3 c; - auto rc = fread(&c, sizeof(c), 1, fp); - if (rc != 1) { - throw std::runtime_error(LOCATION + "Could not read cluster"); - } - --m_num_left; - return c; -} - -ClusterVector ClusterFile::read_frame(){ - if (m_mode != "r") { - throw std::runtime_error(LOCATION + "File not opened for reading"); - } - if (m_noise_map || m_roi){ - return read_frame_with_cut(); - }else{ - return read_frame_without_cut(); - } -} - -ClusterVector ClusterFile::read_frame_without_cut() { - if (m_mode != "r") { - throw std::runtime_error("File not opened for reading"); - } - if (m_num_left) { - throw std::runtime_error( - "There are still photons left in the last frame"); - } - int32_t frame_number; - if (fread(&frame_number, sizeof(frame_number), 1, fp) != 1) { - throw std::runtime_error(LOCATION + "Could not read frame number"); - } - - int32_t n_clusters; // Saved as 32bit integer in the cluster file - if (fread(&n_clusters, sizeof(n_clusters), 1, fp) != 1) { - throw std::runtime_error(LOCATION + "Could not read number of clusters"); - } - - ClusterVector clusters(3, 3, n_clusters); - clusters.set_frame_number(frame_number); - - if (fread(clusters.data(), clusters.item_size(), n_clusters, fp) != - static_cast(n_clusters)) { - throw std::runtime_error(LOCATION + "Could not read clusters"); - } - clusters.resize(n_clusters); - if (m_gain_map) - clusters.apply_gain_map(m_gain_map->view()); - return clusters; -} - -ClusterVector ClusterFile::read_frame_with_cut() { - if (m_mode != "r") { - throw std::runtime_error("File not opened for reading"); - } - if (m_num_left) { - throw std::runtime_error( - "There are still photons left in the last frame"); - } - int32_t frame_number; - if (fread(&frame_number, sizeof(frame_number), 1, fp) != 1) { - throw std::runtime_error("Could not read frame number"); - } - - - if (fread(&m_num_left, sizeof(m_num_left), 1, fp) != 1) { - throw std::runtime_error("Could not read number of clusters"); - } - - ClusterVector clusters(3, 3); - clusters.reserve(m_num_left); - clusters.set_frame_number(frame_number); - while(m_num_left){ - Cluster3x3 c = read_one_cluster(); - if(is_selected(c)){ - clusters.push_back(c.x, c.y, reinterpret_cast(c.data)); - } - } - if (m_gain_map) - clusters.apply_gain_map(m_gain_map->view()); - return clusters; -} - - - -bool ClusterFile::is_selected(Cluster3x3 &cl) { - //Should fail fast - if (m_roi) { - if (!(m_roi->contains(cl.x, cl.y))) { - return false; - } - } - if (m_noise_map){ - int32_t sum_1x1 = cl.data[4]; // central pixel - int32_t sum_2x2 = cl.sum_2x2(); // highest sum of 2x2 subclusters - int32_t sum_3x3 = cl.sum(); // sum of all pixels - - auto noise = (*m_noise_map)(cl.y, cl.x); //TODO! check if this is correct - if (sum_1x1 <= noise || sum_2x2 <= 2 * noise || sum_3x3 <= 3 * noise) { - return false; - } - } - //we passed all checks - return true; -} - -NDArray calculate_eta2(ClusterVector &clusters) { - //TOTO! make work with 2x2 clusters - NDArray eta2({static_cast(clusters.size()), 2}); - - if (clusters.cluster_size_x() == 3 || clusters.cluster_size_y() == 3) { - for (size_t i = 0; i < clusters.size(); i++) { - auto e = calculate_eta2(clusters.at(i)); - eta2(i, 0) = e.x; - eta2(i, 1) = e.y; - } - }else if(clusters.cluster_size_x() == 2 || clusters.cluster_size_y() == 2){ - for (size_t i = 0; i < clusters.size(); i++) { - auto e = calculate_eta2(clusters.at(i)); - eta2(i, 0) = e.x; - eta2(i, 1) = e.y; - } - }else{ - throw std::runtime_error("Only 3x3 and 2x2 clusters are supported"); - } - - return eta2; -} - -/** - * @brief Calculate the eta2 values for a 3x3 cluster and return them in a Eta2 struct - * containing etay, etax and the corner of the cluster. -*/ -Eta2 calculate_eta2(Cluster3x3 &cl) { - Eta2 eta{}; - - std::array tot2; - tot2[0] = cl.data[0] + cl.data[1] + cl.data[3] + cl.data[4]; - tot2[1] = cl.data[1] + cl.data[2] + cl.data[4] + cl.data[5]; - tot2[2] = cl.data[3] + cl.data[4] + cl.data[6] + cl.data[7]; - tot2[3] = cl.data[4] + cl.data[5] + cl.data[7] + cl.data[8]; - - auto c = std::max_element(tot2.begin(), tot2.end()) - tot2.begin(); - eta.sum = tot2[c]; - switch (c) { - case cBottomLeft: - if ((cl.data[3] + cl.data[4]) != 0) - eta.x = - static_cast(cl.data[4]) / (cl.data[3] + cl.data[4]); - if ((cl.data[1] + cl.data[4]) != 0) - eta.y = - static_cast(cl.data[4]) / (cl.data[1] + cl.data[4]); - eta.c = cBottomLeft; - break; - case cBottomRight: - if ((cl.data[2] + cl.data[5]) != 0) - eta.x = - static_cast(cl.data[5]) / (cl.data[4] + cl.data[5]); - if ((cl.data[1] + cl.data[4]) != 0) - eta.y = - static_cast(cl.data[4]) / (cl.data[1] + cl.data[4]); - eta.c = cBottomRight; - break; - case cTopLeft: - if ((cl.data[7] + cl.data[4]) != 0) - eta.x = - static_cast(cl.data[4]) / (cl.data[3] + cl.data[4]); - if ((cl.data[7] + cl.data[4]) != 0) - eta.y = - static_cast(cl.data[7]) / (cl.data[7] + cl.data[4]); - eta.c = cTopLeft; - break; - case cTopRight: - if ((cl.data[5] + cl.data[4]) != 0) - eta.x = - static_cast(cl.data[5]) / (cl.data[5] + cl.data[4]); - if ((cl.data[7] + cl.data[4]) != 0) - eta.y = - static_cast(cl.data[7]) / (cl.data[7] + cl.data[4]); - eta.c = cTopRight; - break; - // no default to allow compiler to warn about missing cases - } - return eta; -} - - -Eta2 calculate_eta2(Cluster2x2 &cl) { - Eta2 eta{}; - if ((cl.data[0] + cl.data[1]) != 0) - eta.x = static_cast(cl.data[1]) / (cl.data[0] + cl.data[1]); - if ((cl.data[0] + cl.data[2]) != 0) - eta.y = static_cast(cl.data[2]) / (cl.data[0] + cl.data[2]); - eta.sum = cl.data[0] + cl.data[1] + cl.data[2]+ cl.data[3]; - eta.c = cBottomLeft; //TODO! This is not correct, but need to put something - return eta; -} - - -} // namespace aare \ No newline at end of file diff --git a/src/Interpolator.cpp b/src/Interpolator.cpp index ecc3e61..4bc2b34 100644 --- a/src/Interpolator.cpp +++ b/src/Interpolator.cpp @@ -53,90 +53,4 @@ Interpolator::Interpolator(NDView etacube, NDView xbins, } } -<<<<<<< HEAD -======= -std::vector Interpolator::interpolate(const ClusterVector& clusters) { - std::vector photons; - photons.reserve(clusters.size()); - - if (clusters.cluster_size_x() == 3 || clusters.cluster_size_y() == 3) { - for (size_t i = 0; i(i); - Eta2 eta= calculate_eta2(cluster); - - Photon photon; - photon.x = cluster.x; - photon.y = cluster.y; - photon.energy = eta.sum; - - - //Finding the index of the last element that is smaller - //should work fine as long as we have many bins - auto ie = last_smaller(m_energy_bins, photon.energy); - auto ix = last_smaller(m_etabinsx, eta.x); - auto iy = last_smaller(m_etabinsy, eta.y); - - double dX{}, dY{}; - // cBottomLeft = 0, - // cBottomRight = 1, - // cTopLeft = 2, - // cTopRight = 3 - switch (eta.c) { - case cTopLeft: - dX = -1.; - dY = 0.; - break; - case cTopRight:; - dX = 0.; - dY = 0.; - break; - case cBottomLeft: - dX = -1.; - dY = -1.; - break; - case cBottomRight: - dX = 0.; - dY = -1.; - break; - } - photon.x += m_ietax(ix, iy, ie)*2 + dX; - photon.y += m_ietay(ix, iy, ie)*2 + dY; - photons.push_back(photon); - } - }else if(clusters.cluster_size_x() == 2 || clusters.cluster_size_y() == 2){ - for (size_t i = 0; i(i); - Eta2 eta= calculate_eta2(cluster); - - Photon photon; - photon.x = cluster.x; - photon.y = cluster.y; - photon.energy = eta.sum; - - //Now do some actual interpolation. - //Find which energy bin the cluster is in - // auto ie = nearest_index(m_energy_bins, photon.energy)-1; - // auto ix = nearest_index(m_etabinsx, eta.x)-1; - // auto iy = nearest_index(m_etabinsy, eta.y)-1; - //Finding the index of the last element that is smaller - //should work fine as long as we have many bins - auto ie = last_smaller(m_energy_bins, photon.energy); - auto ix = last_smaller(m_etabinsx, eta.x); - auto iy = last_smaller(m_etabinsy, eta.y); - - photon.x += m_ietax(ix, iy, ie)*2; //eta goes between 0 and 1 but we could move the hit anywhere in the 2x2 - photon.y += m_ietay(ix, iy, ie)*2; - photons.push_back(photon); - } - - }else{ - throw std::runtime_error("Only 3x3 and 2x2 clusters are supported for interpolation"); - } - - - return photons; -} - ->>>>>>> developer } // namespace aare \ No newline at end of file From 113f34cc98457f135456578ccdde3eb9430da261 Mon Sep 17 00:00:00 2001 From: froejdh_e Date: Thu, 10 Apr 2025 16:50:04 +0200 Subject: [PATCH 33/51] fixes --- include/aare/ClusterFile.hpp | 2 +- include/aare/ClusterVector.hpp | 2 +- python/src/cluster.hpp | 3 +- python/src/np_helper.hpp | 4 +- src/ClusterFile.test.cpp | 114 +++++++++++++++++++++++++++++++++ src/ClusterVector.test.cpp | 24 +++++++ 6 files changed, 144 insertions(+), 5 deletions(-) diff --git a/include/aare/ClusterFile.hpp b/include/aare/ClusterFile.hpp index ff5d338..7248dc2 100644 --- a/include/aare/ClusterFile.hpp +++ b/include/aare/ClusterFile.hpp @@ -236,7 +236,7 @@ ClusterFile::read_clusters_without_cut(size_t n_clusters) { uint32_t nph = m_num_left; // number of clusters in frame needs to be 4 // auto buf = reinterpret_cast(clusters.data()); - auto buf = clusters.data(); + auto buf = reinterpret_cast(clusters.data()); // if there are photons left from previous frame read them first if (nph) { if (nph > n_clusters) { diff --git a/include/aare/ClusterVector.hpp b/include/aare/ClusterVector.hpp index 13ec882..eae2118 100644 --- a/include/aare/ClusterVector.hpp +++ b/include/aare/ClusterVector.hpp @@ -299,7 +299,7 @@ class ClusterVector> { */ ClusterVector(size_t capacity = 1024, uint64_t frame_number = 0) : m_frame_number(frame_number) { - m_data.reserve(capacity); + m_data.resize(capacity); } // Move constructor diff --git a/python/src/cluster.hpp b/python/src/cluster.hpp index f6d3636..755f595 100644 --- a/python/src/cluster.hpp +++ b/python/src/cluster.hpp @@ -80,11 +80,12 @@ void define_cluster_vector(py::module &m, const std::string &typestr) { self.push_back(cluster); }) + // implement push_back .def_property_readonly("size", &ClusterVector::size) .def("item_size", &ClusterVector::item_size) .def_property_readonly("fmt", - [typestr]() { return fmt_format; }) + [typestr](ClusterVector &self) { return fmt_format; }) .def_property_readonly("cluster_size_x", &ClusterVector::cluster_size_x) diff --git a/python/src/np_helper.hpp b/python/src/np_helper.hpp index 98be52f..3d3ee3c 100644 --- a/python/src/np_helper.hpp +++ b/python/src/np_helper.hpp @@ -74,10 +74,10 @@ template > { static std::string value() { - return fmt::format("T{{{}:x;{}:y;{}:data;}}", + return fmt::format("T{{{}:x:{}:y:{}:data:}}", py::format_descriptor::format(), py::format_descriptor::format(), - fmt::format("{}{}", ClusterSizeX * ClusterSizeY, + fmt::format("({},{}){}", ClusterSizeX, ClusterSizeY, py::format_descriptor::format())); } }; diff --git a/src/ClusterFile.test.cpp b/src/ClusterFile.test.cpp index f689b69..d5fdf7c 100644 --- a/src/ClusterFile.test.cpp +++ b/src/ClusterFile.test.cpp @@ -47,6 +47,106 @@ TEST_CASE("Read one frame using ROI", "[.files]") { TEST_CASE("Read clusters from single frame file", "[.files]") { +// frame_number, num_clusters [135] 97 +// [ 1 200] [0 1 2 3 4 5 6 7 8] +// [ 2 201] [ 9 10 11 12 13 14 15 16 17] +// [ 3 202] [18 19 20 21 22 23 24 25 26] +// [ 4 203] [27 28 29 30 31 32 33 34 35] +// [ 5 204] [36 37 38 39 40 41 42 43 44] +// [ 6 205] [45 46 47 48 49 50 51 52 53] +// [ 7 206] [54 55 56 57 58 59 60 61 62] +// [ 8 207] [63 64 65 66 67 68 69 70 71] +// [ 9 208] [72 73 74 75 76 77 78 79 80] +// [ 10 209] [81 82 83 84 85 86 87 88 89] +// [ 11 210] [90 91 92 93 94 95 96 97 98] +// [ 12 211] [ 99 100 101 102 103 104 105 106 107] +// [ 13 212] [108 109 110 111 112 113 114 115 116] +// [ 14 213] [117 118 119 120 121 122 123 124 125] +// [ 15 214] [126 127 128 129 130 131 132 133 134] +// [ 16 215] [135 136 137 138 139 140 141 142 143] +// [ 17 216] [144 145 146 147 148 149 150 151 152] +// [ 18 217] [153 154 155 156 157 158 159 160 161] +// [ 19 218] [162 163 164 165 166 167 168 169 170] +// [ 20 219] [171 172 173 174 175 176 177 178 179] +// [ 21 220] [180 181 182 183 184 185 186 187 188] +// [ 22 221] [189 190 191 192 193 194 195 196 197] +// [ 23 222] [198 199 200 201 202 203 204 205 206] +// [ 24 223] [207 208 209 210 211 212 213 214 215] +// [ 25 224] [216 217 218 219 220 221 222 223 224] +// [ 26 225] [225 226 227 228 229 230 231 232 233] +// [ 27 226] [234 235 236 237 238 239 240 241 242] +// [ 28 227] [243 244 245 246 247 248 249 250 251] +// [ 29 228] [252 253 254 255 256 257 258 259 260] +// [ 30 229] [261 262 263 264 265 266 267 268 269] +// [ 31 230] [270 271 272 273 274 275 276 277 278] +// [ 32 231] [279 280 281 282 283 284 285 286 287] +// [ 33 232] [288 289 290 291 292 293 294 295 296] +// [ 34 233] [297 298 299 300 301 302 303 304 305] +// [ 35 234] [306 307 308 309 310 311 312 313 314] +// [ 36 235] [315 316 317 318 319 320 321 322 323] +// [ 37 236] [324 325 326 327 328 329 330 331 332] +// [ 38 237] [333 334 335 336 337 338 339 340 341] +// [ 39 238] [342 343 344 345 346 347 348 349 350] +// [ 40 239] [351 352 353 354 355 356 357 358 359] +// [ 41 240] [360 361 362 363 364 365 366 367 368] +// [ 42 241] [369 370 371 372 373 374 375 376 377] +// [ 43 242] [378 379 380 381 382 383 384 385 386] +// [ 44 243] [387 388 389 390 391 392 393 394 395] +// [ 45 244] [396 397 398 399 400 401 402 403 404] +// [ 46 245] [405 406 407 408 409 410 411 412 413] +// [ 47 246] [414 415 416 417 418 419 420 421 422] +// [ 48 247] [423 424 425 426 427 428 429 430 431] +// [ 49 248] [432 433 434 435 436 437 438 439 440] +// [ 50 249] [441 442 443 444 445 446 447 448 449] +// [ 51 250] [450 451 452 453 454 455 456 457 458] +// [ 52 251] [459 460 461 462 463 464 465 466 467] +// [ 53 252] [468 469 470 471 472 473 474 475 476] +// [ 54 253] [477 478 479 480 481 482 483 484 485] +// [ 55 254] [486 487 488 489 490 491 492 493 494] +// [ 56 255] [495 496 497 498 499 500 501 502 503] +// [ 57 256] [504 505 506 507 508 509 510 511 512] +// [ 58 257] [513 514 515 516 517 518 519 520 521] +// [ 59 258] [522 523 524 525 526 527 528 529 530] +// [ 60 259] [531 532 533 534 535 536 537 538 539] +// [ 61 260] [540 541 542 543 544 545 546 547 548] +// [ 62 261] [549 550 551 552 553 554 555 556 557] +// [ 63 262] [558 559 560 561 562 563 564 565 566] +// [ 64 263] [567 568 569 570 571 572 573 574 575] +// [ 65 264] [576 577 578 579 580 581 582 583 584] +// [ 66 265] [585 586 587 588 589 590 591 592 593] +// [ 67 266] [594 595 596 597 598 599 600 601 602] +// [ 68 267] [603 604 605 606 607 608 609 610 611] +// [ 69 268] [612 613 614 615 616 617 618 619 620] +// [ 70 269] [621 622 623 624 625 626 627 628 629] +// [ 71 270] [630 631 632 633 634 635 636 637 638] +// [ 72 271] [639 640 641 642 643 644 645 646 647] +// [ 73 272] [648 649 650 651 652 653 654 655 656] +// [ 74 273] [657 658 659 660 661 662 663 664 665] +// [ 75 274] [666 667 668 669 670 671 672 673 674] +// [ 76 275] [675 676 677 678 679 680 681 682 683] +// [ 77 276] [684 685 686 687 688 689 690 691 692] +// [ 78 277] [693 694 695 696 697 698 699 700 701] +// [ 79 278] [702 703 704 705 706 707 708 709 710] +// [ 80 279] [711 712 713 714 715 716 717 718 719] +// [ 81 280] [720 721 722 723 724 725 726 727 728] +// [ 82 281] [729 730 731 732 733 734 735 736 737] +// [ 83 282] [738 739 740 741 742 743 744 745 746] +// [ 84 283] [747 748 749 750 751 752 753 754 755] +// [ 85 284] [756 757 758 759 760 761 762 763 764] +// [ 86 285] [765 766 767 768 769 770 771 772 773] +// [ 87 286] [774 775 776 777 778 779 780 781 782] +// [ 88 287] [783 784 785 786 787 788 789 790 791] +// [ 89 288] [792 793 794 795 796 797 798 799 800] +// [ 90 289] [801 802 803 804 805 806 807 808 809] +// [ 91 290] [810 811 812 813 814 815 816 817 818] +// [ 92 291] [819 820 821 822 823 824 825 826 827] +// [ 93 292] [828 829 830 831 832 833 834 835 836] +// [ 94 293] [837 838 839 840 841 842 843 844 845] +// [ 95 294] [846 847 848 849 850 851 852 853 854] +// [ 96 295] [855 856 857 858 859 860 861 862 863] +// [ 97 296] [864 865 866 867 868 869 870 871 872] + + auto fpath = test_data_path() / "clust" / "single_frame_97_clustrers.clust"; REQUIRE(std::filesystem::exists(fpath)); @@ -68,5 +168,19 @@ TEST_CASE("Read clusters from single frame file", "[.files]") { auto clusters = f.read_clusters(97); REQUIRE(clusters.size() == 97); REQUIRE(clusters.frame_number() == 135); + + REQUIRE(clusters.at(0).x == 1); + REQUIRE(clusters.at(0).y == 200); } } + + + +TEST_CASE("Read clusters", "[.files]"){ + // beam_En700eV_-40deg_300V_10us_d0_f0_100.clust + auto fpath = test_data_path() / "clust" / "beam_En700eV_-40deg_300V_10us_d0_f0_100.clust"; + REQUIRE(std::filesystem::exists(fpath)); + + ClusterFile> f(fpath); + auto clusters = f.read_clusters(500); +} diff --git a/src/ClusterVector.test.cpp b/src/ClusterVector.test.cpp index 1880355..5a5abe0 100644 --- a/src/ClusterVector.test.cpp +++ b/src/ClusterVector.test.cpp @@ -8,6 +8,30 @@ using aare::Cluster; using aare::ClusterVector; + +TEST_CASE("item_size return the size of the cluster stored"){ + using C1 = Cluster; + ClusterVector cv(4); + CHECK(cv.item_size() == sizeof(C1)); + + //Sanity check + //2*2*4 = 16 bytes of data for the cluster + // 2*2 = 4 bytes for the x and y coordinates + REQUIRE(cv.item_size() == 20); + + using C2 = Cluster; + ClusterVector cv2(4); + CHECK(cv2.item_size() == sizeof(C2)); + + using C3 = Cluster; + ClusterVector cv3(4); + CHECK(cv3.item_size() == sizeof(C3)); + + using C4 = Cluster; + ClusterVector cv4(4); + CHECK(cv4.item_size() == sizeof(C4)); +} + TEST_CASE("ClusterVector 2x2 int32_t capacity 4, push back then read", "[.ClusterVector]") { From 92f5421481c05634fd54e018245d8f5530721f28 Mon Sep 17 00:00:00 2001 From: froejdh_e Date: Thu, 10 Apr 2025 16:58:47 +0200 Subject: [PATCH 34/51] np test --- python/tests/test_Cluster.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/python/tests/test_Cluster.py b/python/tests/test_Cluster.py index 29d5ad9..e24bcf8 100644 --- a/python/tests/test_Cluster.py +++ b/python/tests/test_Cluster.py @@ -5,6 +5,12 @@ import aare._aare as aare from conftest import test_data_path +def test_cluster_vector_can_be_converted_to_numpy(): + cv = aare.ClusterVector_Cluster3x3i() + arr = np.array(cv, copy=False) + assert arr.shape == (0,) # 4 for x, y, size, energy and 9 for the cluster data + + def test_ClusterVector(): """Test ClusterVector""" From e71569b15ec3385212fcbb5b6ec6fc8dea6c0386 Mon Sep 17 00:00:00 2001 From: froejdh_e Date: Fri, 11 Apr 2025 13:38:33 +0200 Subject: [PATCH 35/51] resize before read --- include/aare/ClusterFile.hpp | 3 ++- include/aare/ClusterVector.hpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/aare/ClusterFile.hpp b/include/aare/ClusterFile.hpp index 7248dc2..f58d2d6 100644 --- a/include/aare/ClusterFile.hpp +++ b/include/aare/ClusterFile.hpp @@ -229,6 +229,7 @@ ClusterFile::read_clusters_without_cut(size_t n_clusters) { } ClusterVector clusters(n_clusters); + clusters.resize(n_clusters); int32_t iframe = 0; // frame number needs to be 4 bytes! size_t nph_read = 0; @@ -283,7 +284,7 @@ template ClusterVector ClusterFile::read_clusters_with_cut(size_t n_clusters) { ClusterVector clusters; - clusters.reserve(n_clusters); + clusters.resize(n_clusters); // if there are photons left from previous frame read them first if (m_num_left) { diff --git a/include/aare/ClusterVector.hpp b/include/aare/ClusterVector.hpp index eae2118..13ec882 100644 --- a/include/aare/ClusterVector.hpp +++ b/include/aare/ClusterVector.hpp @@ -299,7 +299,7 @@ class ClusterVector> { */ ClusterVector(size_t capacity = 1024, uint64_t frame_number = 0) : m_frame_number(frame_number) { - m_data.resize(capacity); + m_data.reserve(capacity); } // Move constructor From 15e52565a99aae6be03b41088f7034b2376ac348 Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Fri, 11 Apr 2025 14:35:20 +0200 Subject: [PATCH 36/51] dont convert to byte --- include/aare/ClusterFile.hpp | 10 +- include/aare/ClusterVector.hpp | 2 +- python/src/cluster.hpp | 9 +- src/ClusterFile.test.cpp | 204 ++++++++++++++++----------------- 4 files changed, 113 insertions(+), 112 deletions(-) diff --git a/include/aare/ClusterFile.hpp b/include/aare/ClusterFile.hpp index f58d2d6..45df8a0 100644 --- a/include/aare/ClusterFile.hpp +++ b/include/aare/ClusterFile.hpp @@ -236,8 +236,7 @@ ClusterFile::read_clusters_without_cut(size_t n_clusters) { uint32_t nn = m_num_left; uint32_t nph = m_num_left; // number of clusters in frame needs to be 4 - // auto buf = reinterpret_cast(clusters.data()); - auto buf = reinterpret_cast(clusters.data()); + auto buf = clusters.data(); // if there are photons left from previous frame read them first if (nph) { if (nph > n_clusters) { @@ -247,8 +246,7 @@ ClusterFile::read_clusters_without_cut(size_t n_clusters) { } else { nn = nph; } - nph_read += fread((buf + nph_read * clusters.item_size()), - clusters.item_size(), nn, fp); + nph_read += fread((buf + nph_read), clusters.item_size(), nn, fp); m_num_left = nph - nn; // write back the number of photons left } @@ -263,8 +261,8 @@ ClusterFile::read_clusters_without_cut(size_t n_clusters) { else nn = nph; - nph_read += fread((buf + nph_read * clusters.item_size()), - clusters.item_size(), nn, fp); + nph_read += + fread((buf + nph_read), clusters.item_size(), nn, fp); m_num_left = nph - nn; } if (nph_read >= n_clusters) diff --git a/include/aare/ClusterVector.hpp b/include/aare/ClusterVector.hpp index 13ec882..22315cc 100644 --- a/include/aare/ClusterVector.hpp +++ b/include/aare/ClusterVector.hpp @@ -297,7 +297,7 @@ class ClusterVector> { * @param frame_number frame number of the clusters. Default is 0, which is * also used to indicate that the clusters come from many frames */ - ClusterVector(size_t capacity = 1024, uint64_t frame_number = 0) + ClusterVector(size_t capacity = 300, uint64_t frame_number = 0) : m_frame_number(frame_number) { m_data.reserve(capacity); } diff --git a/python/src/cluster.hpp b/python/src/cluster.hpp index 755f595..a06bcdd 100644 --- a/python/src/cluster.hpp +++ b/python/src/cluster.hpp @@ -18,6 +18,9 @@ using pd_type = double; using namespace aare; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" + template void define_cluster(py::module &m, const std::string &typestr) { @@ -80,12 +83,13 @@ void define_cluster_vector(py::module &m, const std::string &typestr) { self.push_back(cluster); }) - // implement push_back .def_property_readonly("size", &ClusterVector::size) .def("item_size", &ClusterVector::item_size) .def_property_readonly("fmt", - [typestr](ClusterVector &self) { return fmt_format; }) + [typestr](ClusterVector &self) { + return fmt_format; + }) .def_property_readonly("cluster_size_x", &ClusterVector::cluster_size_x) @@ -269,3 +273,4 @@ void define_cluster_finder_bindings(py::module &m, const std::string &typestr) { return hitmap; }); } +#pragma GCC diagnostic pop diff --git a/src/ClusterFile.test.cpp b/src/ClusterFile.test.cpp index d5fdf7c..1ee54e7 100644 --- a/src/ClusterFile.test.cpp +++ b/src/ClusterFile.test.cpp @@ -47,105 +47,104 @@ TEST_CASE("Read one frame using ROI", "[.files]") { TEST_CASE("Read clusters from single frame file", "[.files]") { -// frame_number, num_clusters [135] 97 -// [ 1 200] [0 1 2 3 4 5 6 7 8] -// [ 2 201] [ 9 10 11 12 13 14 15 16 17] -// [ 3 202] [18 19 20 21 22 23 24 25 26] -// [ 4 203] [27 28 29 30 31 32 33 34 35] -// [ 5 204] [36 37 38 39 40 41 42 43 44] -// [ 6 205] [45 46 47 48 49 50 51 52 53] -// [ 7 206] [54 55 56 57 58 59 60 61 62] -// [ 8 207] [63 64 65 66 67 68 69 70 71] -// [ 9 208] [72 73 74 75 76 77 78 79 80] -// [ 10 209] [81 82 83 84 85 86 87 88 89] -// [ 11 210] [90 91 92 93 94 95 96 97 98] -// [ 12 211] [ 99 100 101 102 103 104 105 106 107] -// [ 13 212] [108 109 110 111 112 113 114 115 116] -// [ 14 213] [117 118 119 120 121 122 123 124 125] -// [ 15 214] [126 127 128 129 130 131 132 133 134] -// [ 16 215] [135 136 137 138 139 140 141 142 143] -// [ 17 216] [144 145 146 147 148 149 150 151 152] -// [ 18 217] [153 154 155 156 157 158 159 160 161] -// [ 19 218] [162 163 164 165 166 167 168 169 170] -// [ 20 219] [171 172 173 174 175 176 177 178 179] -// [ 21 220] [180 181 182 183 184 185 186 187 188] -// [ 22 221] [189 190 191 192 193 194 195 196 197] -// [ 23 222] [198 199 200 201 202 203 204 205 206] -// [ 24 223] [207 208 209 210 211 212 213 214 215] -// [ 25 224] [216 217 218 219 220 221 222 223 224] -// [ 26 225] [225 226 227 228 229 230 231 232 233] -// [ 27 226] [234 235 236 237 238 239 240 241 242] -// [ 28 227] [243 244 245 246 247 248 249 250 251] -// [ 29 228] [252 253 254 255 256 257 258 259 260] -// [ 30 229] [261 262 263 264 265 266 267 268 269] -// [ 31 230] [270 271 272 273 274 275 276 277 278] -// [ 32 231] [279 280 281 282 283 284 285 286 287] -// [ 33 232] [288 289 290 291 292 293 294 295 296] -// [ 34 233] [297 298 299 300 301 302 303 304 305] -// [ 35 234] [306 307 308 309 310 311 312 313 314] -// [ 36 235] [315 316 317 318 319 320 321 322 323] -// [ 37 236] [324 325 326 327 328 329 330 331 332] -// [ 38 237] [333 334 335 336 337 338 339 340 341] -// [ 39 238] [342 343 344 345 346 347 348 349 350] -// [ 40 239] [351 352 353 354 355 356 357 358 359] -// [ 41 240] [360 361 362 363 364 365 366 367 368] -// [ 42 241] [369 370 371 372 373 374 375 376 377] -// [ 43 242] [378 379 380 381 382 383 384 385 386] -// [ 44 243] [387 388 389 390 391 392 393 394 395] -// [ 45 244] [396 397 398 399 400 401 402 403 404] -// [ 46 245] [405 406 407 408 409 410 411 412 413] -// [ 47 246] [414 415 416 417 418 419 420 421 422] -// [ 48 247] [423 424 425 426 427 428 429 430 431] -// [ 49 248] [432 433 434 435 436 437 438 439 440] -// [ 50 249] [441 442 443 444 445 446 447 448 449] -// [ 51 250] [450 451 452 453 454 455 456 457 458] -// [ 52 251] [459 460 461 462 463 464 465 466 467] -// [ 53 252] [468 469 470 471 472 473 474 475 476] -// [ 54 253] [477 478 479 480 481 482 483 484 485] -// [ 55 254] [486 487 488 489 490 491 492 493 494] -// [ 56 255] [495 496 497 498 499 500 501 502 503] -// [ 57 256] [504 505 506 507 508 509 510 511 512] -// [ 58 257] [513 514 515 516 517 518 519 520 521] -// [ 59 258] [522 523 524 525 526 527 528 529 530] -// [ 60 259] [531 532 533 534 535 536 537 538 539] -// [ 61 260] [540 541 542 543 544 545 546 547 548] -// [ 62 261] [549 550 551 552 553 554 555 556 557] -// [ 63 262] [558 559 560 561 562 563 564 565 566] -// [ 64 263] [567 568 569 570 571 572 573 574 575] -// [ 65 264] [576 577 578 579 580 581 582 583 584] -// [ 66 265] [585 586 587 588 589 590 591 592 593] -// [ 67 266] [594 595 596 597 598 599 600 601 602] -// [ 68 267] [603 604 605 606 607 608 609 610 611] -// [ 69 268] [612 613 614 615 616 617 618 619 620] -// [ 70 269] [621 622 623 624 625 626 627 628 629] -// [ 71 270] [630 631 632 633 634 635 636 637 638] -// [ 72 271] [639 640 641 642 643 644 645 646 647] -// [ 73 272] [648 649 650 651 652 653 654 655 656] -// [ 74 273] [657 658 659 660 661 662 663 664 665] -// [ 75 274] [666 667 668 669 670 671 672 673 674] -// [ 76 275] [675 676 677 678 679 680 681 682 683] -// [ 77 276] [684 685 686 687 688 689 690 691 692] -// [ 78 277] [693 694 695 696 697 698 699 700 701] -// [ 79 278] [702 703 704 705 706 707 708 709 710] -// [ 80 279] [711 712 713 714 715 716 717 718 719] -// [ 81 280] [720 721 722 723 724 725 726 727 728] -// [ 82 281] [729 730 731 732 733 734 735 736 737] -// [ 83 282] [738 739 740 741 742 743 744 745 746] -// [ 84 283] [747 748 749 750 751 752 753 754 755] -// [ 85 284] [756 757 758 759 760 761 762 763 764] -// [ 86 285] [765 766 767 768 769 770 771 772 773] -// [ 87 286] [774 775 776 777 778 779 780 781 782] -// [ 88 287] [783 784 785 786 787 788 789 790 791] -// [ 89 288] [792 793 794 795 796 797 798 799 800] -// [ 90 289] [801 802 803 804 805 806 807 808 809] -// [ 91 290] [810 811 812 813 814 815 816 817 818] -// [ 92 291] [819 820 821 822 823 824 825 826 827] -// [ 93 292] [828 829 830 831 832 833 834 835 836] -// [ 94 293] [837 838 839 840 841 842 843 844 845] -// [ 95 294] [846 847 848 849 850 851 852 853 854] -// [ 96 295] [855 856 857 858 859 860 861 862 863] -// [ 97 296] [864 865 866 867 868 869 870 871 872] - + // frame_number, num_clusters [135] 97 + // [ 1 200] [0 1 2 3 4 5 6 7 8] + // [ 2 201] [ 9 10 11 12 13 14 15 16 17] + // [ 3 202] [18 19 20 21 22 23 24 25 26] + // [ 4 203] [27 28 29 30 31 32 33 34 35] + // [ 5 204] [36 37 38 39 40 41 42 43 44] + // [ 6 205] [45 46 47 48 49 50 51 52 53] + // [ 7 206] [54 55 56 57 58 59 60 61 62] + // [ 8 207] [63 64 65 66 67 68 69 70 71] + // [ 9 208] [72 73 74 75 76 77 78 79 80] + // [ 10 209] [81 82 83 84 85 86 87 88 89] + // [ 11 210] [90 91 92 93 94 95 96 97 98] + // [ 12 211] [ 99 100 101 102 103 104 105 106 107] + // [ 13 212] [108 109 110 111 112 113 114 115 116] + // [ 14 213] [117 118 119 120 121 122 123 124 125] + // [ 15 214] [126 127 128 129 130 131 132 133 134] + // [ 16 215] [135 136 137 138 139 140 141 142 143] + // [ 17 216] [144 145 146 147 148 149 150 151 152] + // [ 18 217] [153 154 155 156 157 158 159 160 161] + // [ 19 218] [162 163 164 165 166 167 168 169 170] + // [ 20 219] [171 172 173 174 175 176 177 178 179] + // [ 21 220] [180 181 182 183 184 185 186 187 188] + // [ 22 221] [189 190 191 192 193 194 195 196 197] + // [ 23 222] [198 199 200 201 202 203 204 205 206] + // [ 24 223] [207 208 209 210 211 212 213 214 215] + // [ 25 224] [216 217 218 219 220 221 222 223 224] + // [ 26 225] [225 226 227 228 229 230 231 232 233] + // [ 27 226] [234 235 236 237 238 239 240 241 242] + // [ 28 227] [243 244 245 246 247 248 249 250 251] + // [ 29 228] [252 253 254 255 256 257 258 259 260] + // [ 30 229] [261 262 263 264 265 266 267 268 269] + // [ 31 230] [270 271 272 273 274 275 276 277 278] + // [ 32 231] [279 280 281 282 283 284 285 286 287] + // [ 33 232] [288 289 290 291 292 293 294 295 296] + // [ 34 233] [297 298 299 300 301 302 303 304 305] + // [ 35 234] [306 307 308 309 310 311 312 313 314] + // [ 36 235] [315 316 317 318 319 320 321 322 323] + // [ 37 236] [324 325 326 327 328 329 330 331 332] + // [ 38 237] [333 334 335 336 337 338 339 340 341] + // [ 39 238] [342 343 344 345 346 347 348 349 350] + // [ 40 239] [351 352 353 354 355 356 357 358 359] + // [ 41 240] [360 361 362 363 364 365 366 367 368] + // [ 42 241] [369 370 371 372 373 374 375 376 377] + // [ 43 242] [378 379 380 381 382 383 384 385 386] + // [ 44 243] [387 388 389 390 391 392 393 394 395] + // [ 45 244] [396 397 398 399 400 401 402 403 404] + // [ 46 245] [405 406 407 408 409 410 411 412 413] + // [ 47 246] [414 415 416 417 418 419 420 421 422] + // [ 48 247] [423 424 425 426 427 428 429 430 431] + // [ 49 248] [432 433 434 435 436 437 438 439 440] + // [ 50 249] [441 442 443 444 445 446 447 448 449] + // [ 51 250] [450 451 452 453 454 455 456 457 458] + // [ 52 251] [459 460 461 462 463 464 465 466 467] + // [ 53 252] [468 469 470 471 472 473 474 475 476] + // [ 54 253] [477 478 479 480 481 482 483 484 485] + // [ 55 254] [486 487 488 489 490 491 492 493 494] + // [ 56 255] [495 496 497 498 499 500 501 502 503] + // [ 57 256] [504 505 506 507 508 509 510 511 512] + // [ 58 257] [513 514 515 516 517 518 519 520 521] + // [ 59 258] [522 523 524 525 526 527 528 529 530] + // [ 60 259] [531 532 533 534 535 536 537 538 539] + // [ 61 260] [540 541 542 543 544 545 546 547 548] + // [ 62 261] [549 550 551 552 553 554 555 556 557] + // [ 63 262] [558 559 560 561 562 563 564 565 566] + // [ 64 263] [567 568 569 570 571 572 573 574 575] + // [ 65 264] [576 577 578 579 580 581 582 583 584] + // [ 66 265] [585 586 587 588 589 590 591 592 593] + // [ 67 266] [594 595 596 597 598 599 600 601 602] + // [ 68 267] [603 604 605 606 607 608 609 610 611] + // [ 69 268] [612 613 614 615 616 617 618 619 620] + // [ 70 269] [621 622 623 624 625 626 627 628 629] + // [ 71 270] [630 631 632 633 634 635 636 637 638] + // [ 72 271] [639 640 641 642 643 644 645 646 647] + // [ 73 272] [648 649 650 651 652 653 654 655 656] + // [ 74 273] [657 658 659 660 661 662 663 664 665] + // [ 75 274] [666 667 668 669 670 671 672 673 674] + // [ 76 275] [675 676 677 678 679 680 681 682 683] + // [ 77 276] [684 685 686 687 688 689 690 691 692] + // [ 78 277] [693 694 695 696 697 698 699 700 701] + // [ 79 278] [702 703 704 705 706 707 708 709 710] + // [ 80 279] [711 712 713 714 715 716 717 718 719] + // [ 81 280] [720 721 722 723 724 725 726 727 728] + // [ 82 281] [729 730 731 732 733 734 735 736 737] + // [ 83 282] [738 739 740 741 742 743 744 745 746] + // [ 84 283] [747 748 749 750 751 752 753 754 755] + // [ 85 284] [756 757 758 759 760 761 762 763 764] + // [ 86 285] [765 766 767 768 769 770 771 772 773] + // [ 87 286] [774 775 776 777 778 779 780 781 782] + // [ 88 287] [783 784 785 786 787 788 789 790 791] + // [ 89 288] [792 793 794 795 796 797 798 799 800] + // [ 90 289] [801 802 803 804 805 806 807 808 809] + // [ 91 290] [810 811 812 813 814 815 816 817 818] + // [ 92 291] [819 820 821 822 823 824 825 826 827] + // [ 93 292] [828 829 830 831 832 833 834 835 836] + // [ 94 293] [837 838 839 840 841 842 843 844 845] + // [ 95 294] [846 847 848 849 850 851 852 853 854] + // [ 96 295] [855 856 857 858 859 860 861 862 863] + // [ 97 296] [864 865 866 867 868 869 870 871 872] auto fpath = test_data_path() / "clust" / "single_frame_97_clustrers.clust"; REQUIRE(std::filesystem::exists(fpath)); @@ -174,11 +173,10 @@ TEST_CASE("Read clusters from single frame file", "[.files]") { } } - - -TEST_CASE("Read clusters", "[.files]"){ +TEST_CASE("Read clusters", "[.files]") { // beam_En700eV_-40deg_300V_10us_d0_f0_100.clust - auto fpath = test_data_path() / "clust" / "beam_En700eV_-40deg_300V_10us_d0_f0_100.clust"; + auto fpath = test_data_path() / "clust" / + "beam_En700eV_-40deg_300V_10us_d0_f0_100.clust"; REQUIRE(std::filesystem::exists(fpath)); ClusterFile> f(fpath); From 54def2633439f4ec9adbb2fdabae95f27dae23aa Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Mon, 14 Apr 2025 15:48:09 +0200 Subject: [PATCH 37/51] added ClusterFile tests fixed some bugs in ClusterFile --- CMakeLists.txt | 1 - include/aare/CalculateEta.hpp | 2 +- include/aare/ClusterFile.hpp | 68 ++++++-- include/aare/ClusterFileV2.hpp | 154 ------------------ include/aare/ClusterVector.hpp | 286 ++++----------------------------- python/src/cluster.hpp | 11 ++ src/Cluster.test.cpp | 6 + src/ClusterFile.test.cpp | 184 +++++++++++++++++++-- src/ClusterVector.test.cpp | 21 ++- 9 files changed, 294 insertions(+), 439 deletions(-) delete mode 100644 include/aare/ClusterFileV2.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8bb7667..b57f05f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -384,7 +384,6 @@ set(SourceFiles ${CMAKE_CURRENT_SOURCE_DIR}/src/utils/task.cpp ) - add_library(aare_core STATIC ${SourceFiles}) target_include_directories(aare_core PUBLIC "$" diff --git a/include/aare/CalculateEta.hpp b/include/aare/CalculateEta.hpp index 0aab540..2797233 100644 --- a/include/aare/CalculateEta.hpp +++ b/include/aare/CalculateEta.hpp @@ -33,7 +33,7 @@ template struct Eta2 { }; /** - * @brief Calculate the eta2 values for all clusters in a Clsutervector + * @brief Calculate the eta2 values for all clusters in a Clustervector */ template >> diff --git a/include/aare/ClusterFile.hpp b/include/aare/ClusterFile.hpp index 45df8a0..06de985 100644 --- a/include/aare/ClusterFile.hpp +++ b/include/aare/ClusterFile.hpp @@ -39,9 +39,10 @@ template >> class ClusterFile { FILE *fp{}; + const std::string m_filename{}; uint32_t m_num_left{}; /*Number of photons left in frame*/ size_t m_chunk_size{}; /*Number of clusters to read at a time*/ - const std::string m_mode; /*Mode to open the file in*/ + std::string m_mode; /*Mode to open the file in*/ std::optional m_roi; /*Region of interest, will be applied if set*/ std::optional> m_noise_map; /*Noise map to cut photons, will be applied if set*/ @@ -115,6 +116,11 @@ class ClusterFile { */ void close(); + /** @brief Open the file in specific mode + * + */ + void open(const std::string &mode); + private: ClusterVector read_clusters_with_cut(size_t n_clusters); ClusterVector read_clusters_without_cut(size_t n_clusters); @@ -128,25 +134,25 @@ template ClusterFile::ClusterFile( const std::filesystem::path &fname, size_t chunk_size, const std::string &mode) - : m_chunk_size(chunk_size), m_mode(mode) { + : m_filename(fname.string()), m_chunk_size(chunk_size), m_mode(mode) { if (mode == "r") { - fp = fopen(fname.c_str(), "rb"); + fp = fopen(m_filename.c_str(), "rb"); if (!fp) { throw std::runtime_error("Could not open file for reading: " + - fname.string()); + m_filename); } } else if (mode == "w") { - fp = fopen(fname.c_str(), "wb"); + fp = fopen(m_filename.c_str(), "wb"); if (!fp) { throw std::runtime_error("Could not open file for writing: " + - fname.string()); + m_filename); } } else if (mode == "a") { - fp = fopen(fname.c_str(), "ab"); + fp = fopen(m_filename.c_str(), "ab"); if (!fp) { throw std::runtime_error("Could not open file for appending: " + - fname.string()); + m_filename); } } else { throw std::runtime_error("Unsupported mode: " + mode); @@ -165,6 +171,39 @@ void ClusterFile::close() { fp = nullptr; } } + +template +void ClusterFile::open(const std::string &mode) { + if (fp) { + close(); + } + + if (mode == "r") { + fp = fopen(m_filename.c_str(), "rb"); + if (!fp) { + throw std::runtime_error("Could not open file for reading: " + + m_filename); + } + m_mode = "r"; + } else if (mode == "w") { + fp = fopen(m_filename.c_str(), "wb"); + if (!fp) { + throw std::runtime_error("Could not open file for writing: " + + m_filename); + } + m_mode = "w"; + } else if (mode == "a") { + fp = fopen(m_filename.c_str(), "ab"); + if (!fp) { + throw std::runtime_error("Could not open file for appending: " + + m_filename); + } + m_mode = "a"; + } else { + throw std::runtime_error("Unsupported mode: " + mode); + } +} + template void ClusterFile::set_roi(ROI roi) { m_roi = roi; @@ -197,10 +236,7 @@ void ClusterFile::write_frame( if (m_mode != "w" && m_mode != "a") { throw std::runtime_error("File not opened for writing"); } - if (!(clusters.cluster_size_x() == 3) && - !(clusters.cluster_size_y() == 3)) { - throw std::runtime_error("Only 3x3 clusters are supported"); - } + int32_t frame_number = clusters.frame_number(); fwrite(&frame_number, sizeof(frame_number), 1, fp); uint32_t n_clusters = clusters.size(); @@ -270,7 +306,7 @@ ClusterFile::read_clusters_without_cut(size_t n_clusters) { } } - // Resize the vector to the number of clusters. + // Resize the vector to the number o f clusters. // No new allocation, only change bounds. clusters.resize(nph_read); if (m_gain_map) @@ -282,7 +318,7 @@ template ClusterVector ClusterFile::read_clusters_with_cut(size_t n_clusters) { ClusterVector clusters; - clusters.resize(n_clusters); + clusters.reserve(n_clusters); // if there are photons left from previous frame read them first if (m_num_left) { @@ -375,11 +411,13 @@ ClusterFile::read_frame_without_cut() { ClusterVector clusters(n_clusters); clusters.set_frame_number(frame_number); + clusters.resize(n_clusters); + if (fread(clusters.data(), clusters.item_size(), n_clusters, fp) != static_cast(n_clusters)) { throw std::runtime_error(LOCATION + "Could not read clusters"); } - clusters.resize(n_clusters); + if (m_gain_map) m_gain_map->apply_gain_map(clusters); return clusters; diff --git a/include/aare/ClusterFileV2.hpp b/include/aare/ClusterFileV2.hpp deleted file mode 100644 index 55b8a2b..0000000 --- a/include/aare/ClusterFileV2.hpp +++ /dev/null @@ -1,154 +0,0 @@ -#pragma once -#include "aare/core/defs.hpp" -#include -#include -#include - -namespace aare { -struct ClusterHeader { - int32_t frame_number; - int32_t n_clusters; - std::string to_string() const { - return "frame_number: " + std::to_string(frame_number) + - ", n_clusters: " + std::to_string(n_clusters); - } -}; - -struct ClusterV2_ { - int16_t x; - int16_t y; - std::array data; - std::string to_string(bool detailed = false) const { - if (detailed) { - std::string data_str = "["; - for (auto &d : data) { - data_str += std::to_string(d) + ", "; - } - data_str += "]"; - return "x: " + std::to_string(x) + ", y: " + std::to_string(y) + - ", data: " + data_str; - } - return "x: " + std::to_string(x) + ", y: " + std::to_string(y); - } -}; - -struct ClusterV2 { - ClusterV2_ cluster; - int32_t frame_number; - std::string to_string() const { - return "frame_number: " + std::to_string(frame_number) + ", " + - cluster.to_string(); - } -}; - -/** - * @brief - * important not: fp always points to the clusters header and does not point to - * individual clusters - * - */ -class ClusterFileV2 { - std::filesystem::path m_fpath; - std::string m_mode; - FILE *fp{nullptr}; - - void check_open() { - if (!fp) - throw std::runtime_error( - fmt::format("File: {} not open", m_fpath.string())); - } - - public: - ClusterFileV2(std::filesystem::path const &fpath, std::string const &mode) - : m_fpath(fpath), m_mode(mode) { - if (m_mode != "r" && m_mode != "w") - throw std::invalid_argument("mode must be 'r' or 'w'"); - if (m_mode == "r" && !std::filesystem::exists(m_fpath)) - throw std::invalid_argument("File does not exist"); - if (mode == "r") { - fp = fopen(fpath.string().c_str(), "rb"); - } else if (mode == "w") { - if (std::filesystem::exists(fpath)) { - fp = fopen(fpath.string().c_str(), "r+b"); - } else { - fp = fopen(fpath.string().c_str(), "wb"); - } - } - if (fp == nullptr) { - throw std::runtime_error("Failed to open file"); - } - } - ~ClusterFileV2() { close(); } - std::vector read() { - check_open(); - - ClusterHeader header; - fread(&header, sizeof(ClusterHeader), 1, fp); - std::vector clusters_(header.n_clusters); - fread(clusters_.data(), sizeof(ClusterV2_), header.n_clusters, fp); - std::vector clusters; - for (auto &c : clusters_) { - ClusterV2 cluster; - cluster.cluster = std::move(c); - cluster.frame_number = header.frame_number; - clusters.push_back(cluster); - } - - return clusters; - } - std::vector> read(int n_frames) { - std::vector> clusters; - for (int i = 0; i < n_frames; i++) { - clusters.push_back(read()); - } - return clusters; - } - - size_t write(std::vector const &clusters) { - check_open(); - if (m_mode != "w") - throw std::runtime_error("File not opened in write mode"); - if (clusters.empty()) - return 0; - - ClusterHeader header; - header.frame_number = clusters[0].frame_number; - header.n_clusters = clusters.size(); - fwrite(&header, sizeof(ClusterHeader), 1, fp); - for (auto &c : clusters) { - fwrite(&c.cluster, sizeof(ClusterV2_), 1, fp); - } - return clusters.size(); - } - - size_t write(std::vector> const &clusters) { - check_open(); - if (m_mode != "w") - throw std::runtime_error("File not opened in write mode"); - - size_t n_clusters = 0; - for (auto &c : clusters) { - n_clusters += write(c); - } - return n_clusters; - } - - int seek_to_begin() { return fseek(fp, 0, SEEK_SET); } - int seek_to_end() { return fseek(fp, 0, SEEK_END); } - - int32_t frame_number() { - auto pos = ftell(fp); - ClusterHeader header; - fread(&header, sizeof(ClusterHeader), 1, fp); - fseek(fp, pos, SEEK_SET); - return header.frame_number; - } - - void close() { - if (fp) { - fclose(fp); - fp = nullptr; - } - } -}; -} // namespace aare \ No newline at end of file diff --git a/include/aare/ClusterVector.hpp b/include/aare/ClusterVector.hpp index 22315cc..cc88256 100644 --- a/include/aare/ClusterVector.hpp +++ b/include/aare/ClusterVector.hpp @@ -18,256 +18,6 @@ template >> class ClusterVector; // Forward declaration -/** - * @brief ClusterVector is a container for clusters of various sizes. It uses a - * contiguous memory buffer to store the clusters. It is templated on the data - * type and the coordinate type of the clusters. - * @note push_back can invalidate pointers to elements in the container - * @warning ClusterVector is currently move only to catch unintended copies, but - * this might change since there are probably use cases where copying is needed. - * @tparam T data type of the pixels in the cluster - * @tparam CoordType data type of the x and y coordinates of the cluster - * (normally int16_t) - */ -#if 0 -template -class ClusterVector> { - - std::byte *m_data{}; - size_t m_size{0}; - size_t m_capacity; - uint64_t m_frame_number{0}; // TODO! Check frame number size and type - /** - Format string used in the python bindings to create a numpy - array from the buffer - = - native byte order - h - short - d - double - i - int - */ - constexpr static char m_fmt_base[] = "=h:x:\nh:y:\n({},{}){}:data:"; - - public: - using value_type = T; - using ClusterType = Cluster; - - /** - * @brief Construct a new ClusterVector object - * @param capacity initial capacity of the buffer in number of clusters - * @param frame_number frame number of the clusters. Default is 0, which is - * also used to indicate that the clusters come from many frames - */ - ClusterVector(size_t capacity = 1024, uint64_t frame_number = 0) - : m_capacity(capacity), m_frame_number(frame_number) { - allocate_buffer(m_capacity); - } - - ~ClusterVector() { delete[] m_data; } - - // Move constructor - ClusterVector(ClusterVector &&other) noexcept - : m_data(other.m_data), m_size(other.m_size), - m_capacity(other.m_capacity), m_frame_number(other.m_frame_number) { - other.m_data = nullptr; - other.m_size = 0; - other.m_capacity = 0; - } - - // Move assignment operator - ClusterVector &operator=(ClusterVector &&other) noexcept { - if (this != &other) { - delete[] m_data; - m_data = other.m_data; - m_size = other.m_size; - m_capacity = other.m_capacity; - m_frame_number = other.m_frame_number; - other.m_data = nullptr; - other.m_size = 0; - other.m_capacity = 0; - other.m_frame_number = 0; - } - return *this; - } - - /** - * @brief Reserve space for at least capacity clusters - * @param capacity number of clusters to reserve space for - * @note If capacity is less than the current capacity, the function does - * nothing. - */ - void reserve(size_t capacity) { - if (capacity > m_capacity) { - allocate_buffer(capacity); - } - } - - /** - * @brief Add a cluster to the vector - */ - void push_back(const ClusterType &cluster) { - if (m_size == m_capacity) { - allocate_buffer(m_capacity * 2); - } - std::byte *ptr = element_ptr(m_size); - *reinterpret_cast(ptr) = cluster.x; - ptr += sizeof(CoordType); - *reinterpret_cast(ptr) = cluster.y; - ptr += sizeof(CoordType); - - std::memcpy(ptr, cluster.data, ClusterSizeX * ClusterSizeY * sizeof(T)); - - m_size++; - } - - ClusterVector &operator+=(const ClusterVector &other) { - if (m_size + other.m_size > m_capacity) { - allocate_buffer(m_capacity + other.m_size); - } - std::copy(other.m_data, other.m_data + other.m_size * item_size(), - m_data + m_size * item_size()); - m_size += other.m_size; - return *this; - } - - /** - * @brief Sum the pixels in each cluster - * @return std::vector vector of sums for each cluster - */ - /* - std::vector sum() { - std::vector sums(m_size); - const size_t stride = item_size(); - const size_t n_pixels = ClusterSizeX * ClusterSizeY; - std::byte *ptr = m_data + 2 * sizeof(CoordType); // skip x and y - - for (size_t i = 0; i < m_size; i++) { - sums[i] = - std::accumulate(reinterpret_cast(ptr), - reinterpret_cast(ptr) + n_pixels, T{}); - ptr += stride; - } - return sums; - } - */ - - /** - * @brief Sum the pixels in the 2x2 subcluster with the biggest pixel sum in - * each cluster - * @return std::vector vector of sums for each cluster - */ //TODO if underlying container is a vector use std::for_each - /* - std::vector sum_2x2() { - std::vector sums_2x2(m_size); - - for (size_t i = 0; i < m_size; i++) { - sums_2x2[i] = at(i).max_sum_2x2; - } - return sums_2x2; - } - */ - - /** - * @brief Return the number of clusters in the vector - */ - size_t size() const { return m_size; } - - uint8_t cluster_size_x() const { return ClusterSizeX; } - - uint8_t cluster_size_y() const { return ClusterSizeY; } - - /** - * @brief Return the capacity of the buffer in number of clusters. This is - * the number of clusters that can be stored in the current buffer without - * reallocation. - */ - size_t capacity() const { return m_capacity; } - - /** - * @brief Return the size in bytes of a single cluster - */ - size_t item_size() const { - return 2 * sizeof(CoordType) + ClusterSizeX * ClusterSizeY * sizeof(T); - } - - /** - * @brief Return the offset in bytes for the i-th cluster - */ - size_t element_offset(size_t i) const { return item_size() * i; } - - /** - * @brief Return a pointer to the i-th cluster - */ - std::byte *element_ptr(size_t i) { return m_data + element_offset(i); } - - /** - * @brief Return a pointer to the i-th cluster - */ - const std::byte *element_ptr(size_t i) const { - return m_data + element_offset(i); - } - - std::byte *data() { return m_data; } - std::byte const *data() const { return m_data; } - - /** - * @brief Return a reference to the i-th cluster casted to type V - * @tparam V type of the cluster - */ - ClusterType &at(size_t i) { - return *reinterpret_cast(element_ptr(i)); - } - - const ClusterType &at(size_t i) const { - return *reinterpret_cast(element_ptr(i)); - } - - template const V &at(size_t i) const { - return *reinterpret_cast(element_ptr(i)); - } - - const std::string_view fmt_base() const { - // TODO! how do we match on coord_t? - return m_fmt_base; - } - - /** - * @brief Return the frame number of the clusters. 0 is used to indicate - * that the clusters come from many frames - */ - uint64_t frame_number() const { return m_frame_number; } - - void set_frame_number(uint64_t frame_number) { - m_frame_number = frame_number; - } - - /** - * @brief Resize the vector to contain new_size clusters. If new_size is - * greater than the current capacity, a new buffer is allocated. If the size - * is smaller no memory is freed, size is just updated. - * @param new_size new size of the vector - * @warning The additional clusters are not initialized - */ - void resize(size_t new_size) { - // TODO! Should we initialize the new clusters? - if (new_size > m_capacity) { - allocate_buffer(new_size); - } - m_size = new_size; - } - - private: - void allocate_buffer(size_t new_capacity) { - size_t num_bytes = item_size() * new_capacity; - std::byte *new_data = new std::byte[num_bytes]{}; - std::copy(m_data, m_data + item_size() * m_size, new_data); - delete[] m_data; - m_data = new_data; - m_capacity = new_capacity; - } -}; -#endif - /** * @brief ClusterVector is a container for clusters of various sizes. It * uses a contiguous memory buffer to store the clusters. It is templated on @@ -285,7 +35,7 @@ template > { std::vector> m_data{}; - uint64_t m_frame_number{0}; // TODO! Check frame number size and type + int32_t m_frame_number{0}; // TODO! Check frame number size and type public: using value_type = T; @@ -319,6 +69,33 @@ class ClusterVector> { return *this; } + /** + * @brief Sum the pixels in each cluster + * @return std::vector vector of sums for each cluster + */ + std::vector sum() { + std::vector sums(m_data.size()); + + for (size_t i = 0; i < m_data.size(); i++) { + sums[i] = at(i).sum(); + } + return sums; + } + + /** + * @brief Sum the pixels in the 2x2 subcluster with the biggest pixel sum in + * each cluster + * @return std::vector vector of sums for each cluster + */ //TODO if underlying container is a vector use std::for_each + std::vector sum_2x2() { + std::vector sums_2x2(m_data.size()); + + for (size_t i = 0; i < m_data.size(); i++) { + sums_2x2[i] = at(i).max_sum_2x2().first; + } + return sums_2x2; + } + /** * @brief Reserve space for at least capacity clusters * @param capacity number of clusters to reserve space for @@ -361,7 +138,8 @@ class ClusterVector> { * @brief Return the size in bytes of a single cluster */ size_t item_size() const { - return 2 * sizeof(CoordType) + ClusterSizeX * ClusterSizeY * sizeof(T); + return sizeof(ClusterType); // 2 * sizeof(CoordType) + ClusterSizeX * + // ClusterSizeY * sizeof(T); } ClusterType *data() { return m_data.data(); } @@ -379,9 +157,9 @@ class ClusterVector> { * @brief Return the frame number of the clusters. 0 is used to indicate * that the clusters come from many frames */ - uint64_t frame_number() const { return m_frame_number; } + int32_t frame_number() const { return m_frame_number; } - void set_frame_number(uint64_t frame_number) { + void set_frame_number(int32_t frame_number) { m_frame_number = frame_number; } }; diff --git a/python/src/cluster.hpp b/python/src/cluster.hpp index a06bcdd..96a4f0f 100644 --- a/python/src/cluster.hpp +++ b/python/src/cluster.hpp @@ -83,6 +83,17 @@ void define_cluster_vector(py::module &m, const std::string &typestr) { self.push_back(cluster); }) + .def("sum", + [](ClusterVector &self) { + auto *vec = new std::vector(self.sum()); + return return_vector(vec); + }) + .def("sum_2x2", + [](ClusterVector &self) { + auto *vec = new std::vector(self.sum_2x2()); + return return_vector(vec); + }) + // implement push_back .def_property_readonly("size", &ClusterVector::size) .def("item_size", &ClusterVector::item_size) diff --git a/src/Cluster.test.cpp b/src/Cluster.test.cpp index e502012..879a5e7 100644 --- a/src/Cluster.test.cpp +++ b/src/Cluster.test.cpp @@ -26,3 +26,9 @@ TEST_CASE("Correct Instantiation of Cluster and ClusterVector", CHECK(not is_cluster_v); CHECK(is_cluster_v>); } + +TEST_CASE("Test sum of Cluster", "[.cluster]") { + Cluster cluster{0, 0, {1, 2, 3, 4}}; + + CHECK(cluster.sum() == 10); +} \ No newline at end of file diff --git a/src/ClusterFile.test.cpp b/src/ClusterFile.test.cpp index 1ee54e7..024bed4 100644 --- a/src/ClusterFile.test.cpp +++ b/src/ClusterFile.test.cpp @@ -2,21 +2,29 @@ #include "test_config.hpp" #include "aare/defs.hpp" +#include #include #include using aare::Cluster; using aare::ClusterFile; +using aare::ClusterVector; -TEST_CASE("Read one frame from a a cluster file", "[.files]") { +TEST_CASE("Read one frame from a cluster file", "[.files]") { // We know that the frame has 97 clusters auto fpath = test_data_path() / "clust" / "single_frame_97_clustrers.clust"; REQUIRE(std::filesystem::exists(fpath)); ClusterFile> f(fpath); auto clusters = f.read_frame(); - REQUIRE(clusters.size() == 97); - REQUIRE(clusters.frame_number() == 135); + CHECK(clusters.size() == 97); + CHECK(clusters.frame_number() == 135); + CHECK(clusters.at(0).x == 1); + CHECK(clusters.at(0).y == 200); + int32_t expected_cluster_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; + CHECK(std::equal(std::begin(clusters.at(0).data), + std::end(clusters.at(0).data), + std::begin(expected_cluster_data))); } TEST_CASE("Read one frame using ROI", "[.files]") { @@ -43,6 +51,13 @@ TEST_CASE("Read one frame using ROI", "[.files]") { REQUIRE(c.y >= roi.ymin); REQUIRE(c.y <= roi.ymax); } + + CHECK(clusters.at(0).x == 1); + CHECK(clusters.at(0).y == 200); + int32_t expected_cluster_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; + CHECK(std::equal(std::begin(clusters.at(0).data), + std::end(clusters.at(0).data), + std::begin(expected_cluster_data))); } TEST_CASE("Read clusters from single frame file", "[.files]") { @@ -154,6 +169,12 @@ TEST_CASE("Read clusters from single frame file", "[.files]") { auto clusters = f.read_clusters(50); REQUIRE(clusters.size() == 50); REQUIRE(clusters.frame_number() == 135); + int32_t expected_cluster_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; + REQUIRE(clusters.at(0).x == 1); + REQUIRE(clusters.at(0).y == 200); + CHECK(std::equal(std::begin(clusters.at(0).data), + std::end(clusters.at(0).data), + std::begin(expected_cluster_data))); } SECTION("Read more clusters than available") { ClusterFile> f(fpath); @@ -161,24 +182,169 @@ TEST_CASE("Read clusters from single frame file", "[.files]") { auto clusters = f.read_clusters(100); REQUIRE(clusters.size() == 97); REQUIRE(clusters.frame_number() == 135); + int32_t expected_cluster_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; + REQUIRE(clusters.at(0).x == 1); + REQUIRE(clusters.at(0).y == 200); + CHECK(std::equal(std::begin(clusters.at(0).data), + std::end(clusters.at(0).data), + std::begin(expected_cluster_data))); } SECTION("Read all clusters") { ClusterFile> f(fpath); auto clusters = f.read_clusters(97); REQUIRE(clusters.size() == 97); REQUIRE(clusters.frame_number() == 135); - REQUIRE(clusters.at(0).x == 1); REQUIRE(clusters.at(0).y == 200); + int32_t expected_cluster_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; + CHECK(std::equal(std::begin(clusters.at(0).data), + std::end(clusters.at(0).data), + std::begin(expected_cluster_data))); } } -TEST_CASE("Read clusters", "[.files]") { - // beam_En700eV_-40deg_300V_10us_d0_f0_100.clust - auto fpath = test_data_path() / "clust" / - "beam_En700eV_-40deg_300V_10us_d0_f0_100.clust"; +TEST_CASE("Read clusters from single frame file with ROI", "[.files]") { + auto fpath = test_data_path() / "clust" / "single_frame_97_clustrers.clust"; REQUIRE(std::filesystem::exists(fpath)); ClusterFile> f(fpath); - auto clusters = f.read_clusters(500); + + aare::ROI roi; + roi.xmin = 0; + roi.xmax = 50; + roi.ymin = 200; + roi.ymax = 249; + f.set_roi(roi); + + auto clusters = f.read_clusters(10); + + CHECK(clusters.size() == 10); + CHECK(clusters.frame_number() == 135); + CHECK(clusters.at(0).x == 1); + CHECK(clusters.at(0).y == 200); + int32_t expected_cluster_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; + CHECK(std::equal(std::begin(clusters.at(0).data), + std::end(clusters.at(0).data), + std::begin(expected_cluster_data))); +} + +TEST_CASE("Read cluster from multiple frame file", "[.files]") { + + using ClusterType = Cluster; + + auto fpath = + test_data_path() / "clust" / "Two_frames_2x2double_test_clusters.clust"; + + REQUIRE(std::filesystem::exists(fpath)); + + // Two_frames_2x2double_test_clusters.clust + // frame number, num_clusters 0, 4 + //[10, 20], {0. ,0., 0., 0.} + //[11, 30], {1., 1., 1., 1.} + //[12, 40], {2., 2., 2., 2.} + //[13, 50], {3., 3., 3., 3.} + // 1,4 + //[10, 20], {4., 4., 4., 4.} + //[11, 30], {5., 5., 5., 5.} + //[12, 40], {6., 6., 6., 6.} + //[13, 50], {7., 7., 7., 7.} + + SECTION("Read clusters from both frames") { + ClusterFile f(fpath); + auto clusters = f.read_clusters(2); + REQUIRE(clusters.size() == 2); + REQUIRE(clusters.frame_number() == 0); + + auto clusters1 = f.read_clusters(3); + + REQUIRE(clusters1.size() == 3); + REQUIRE(clusters1.frame_number() == 1); + } + + SECTION("Read all clusters") { + ClusterFile f(fpath); + auto clusters = f.read_clusters(8); + REQUIRE(clusters.size() == 8); + REQUIRE(clusters.frame_number() == 1); + } + + SECTION("Read clusters from one frame") { + ClusterFile f(fpath); + auto clusters = f.read_clusters(2); + REQUIRE(clusters.size() == 2); + REQUIRE(clusters.frame_number() == 0); + + auto clusters1 = f.read_clusters(1); + + REQUIRE(clusters1.size() == 1); + REQUIRE(clusters1.frame_number() == 0); + } +} + +TEST_CASE("Write cluster with potential padding", "[.files][.ClusterFile]") { + + using ClusterType = Cluster; + + REQUIRE(std::filesystem::exists(test_data_path() / "clust")); + + auto fpath = test_data_path() / "clust" / "single_frame_2_clusters.clust"; + + ClusterFile file(fpath, 1000, "w"); + + ClusterVector clustervec(2); + int16_t coordinate = 5; + clustervec.push_back(ClusterType{ + coordinate, coordinate, {0., 0., 0., 0., 0., 0., 0., 0., 0.}}); + clustervec.push_back(ClusterType{ + coordinate, coordinate, {0., 0., 0., 0., 0., 0., 0., 0., 0.}}); + + file.write_frame(clustervec); + + file.close(); + + file.open("r"); + + auto read_cluster_vector = file.read_frame(); + + CHECK(read_cluster_vector.size() == 2); + CHECK(read_cluster_vector.frame_number() == 0); + + CHECK(read_cluster_vector.at(0).x == clustervec.at(0).x); + CHECK(read_cluster_vector.at(0).y == clustervec.at(0).y); + CHECK(std::equal(clustervec.at(0).data, clustervec.at(0).data + 9, + read_cluster_vector.at(0).data, [](double a, double b) { + return std::abs(a - b) < + std::numeric_limits::epsilon(); + })); + + CHECK(read_cluster_vector.at(1).x == clustervec.at(1).x); + CHECK(read_cluster_vector.at(1).y == clustervec.at(1).y); + CHECK(std::equal(clustervec.at(1).data, std::end(clustervec.at(1).data), + read_cluster_vector.at(1).data, [](double a, double b) { + return std::abs(a - b) < + std::numeric_limits::epsilon(); + })); +} + +TEST_CASE("Read frame and modify cluster data", "[.files][.ClusterFile]") { + auto fpath = test_data_path() / "clust" / "single_frame_97_clustrers.clust"; + REQUIRE(std::filesystem::exists(fpath)); + + ClusterFile> f(fpath); + + auto clusters = f.read_frame(); + CHECK(clusters.size() == 97); + CHECK(clusters.frame_number() == 135); + + int32_t expected_cluster_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; + clusters.push_back( + Cluster{0, 0, {0, 1, 2, 3, 4, 5, 6, 7, 8}}); + + CHECK(clusters.size() == 98); + CHECK(clusters.at(0).x == 1); + CHECK(clusters.at(0).y == 200); + + CHECK(std::equal(std::begin(clusters.at(0).data), + std::end(clusters.at(0).data), + std::begin(expected_cluster_data))); } diff --git a/src/ClusterVector.test.cpp b/src/ClusterVector.test.cpp index 5a5abe0..468a707 100644 --- a/src/ClusterVector.test.cpp +++ b/src/ClusterVector.test.cpp @@ -8,15 +8,14 @@ using aare::Cluster; using aare::ClusterVector; - -TEST_CASE("item_size return the size of the cluster stored"){ +TEST_CASE("item_size return the size of the cluster stored") { using C1 = Cluster; ClusterVector cv(4); CHECK(cv.item_size() == sizeof(C1)); - //Sanity check - //2*2*4 = 16 bytes of data for the cluster - // 2*2 = 4 bytes for the x and y coordinates + // Sanity check + // 2*2*4 = 16 bytes of data for the cluster + // 2*2 = 4 bytes for the x and y coordinates REQUIRE(cv.item_size() == 20); using C2 = Cluster; @@ -30,6 +29,18 @@ TEST_CASE("item_size return the size of the cluster stored"){ using C4 = Cluster; ClusterVector cv4(4); CHECK(cv4.item_size() == sizeof(C4)); + + using C5 = Cluster; + ClusterVector cv5(4); + CHECK(cv5.item_size() == sizeof(C5)); + + using C6 = Cluster; + ClusterVector cv6(4); + CHECK(cv6.item_size() == sizeof(C6)); + + using C7 = Cluster; + ClusterVector cv7(4); + CHECK(cv7.item_size() == sizeof(C7)); } TEST_CASE("ClusterVector 2x2 int32_t capacity 4, push back then read", From 7c93632605794825c328cdc293e38cfbb1b74fae Mon Sep 17 00:00:00 2001 From: froejdh_e Date: Mon, 14 Apr 2025 16:38:25 +0200 Subject: [PATCH 38/51] tests and fix --- include/aare/ClusterFile.hpp | 2 +- include/aare/ClusterVector.hpp | 8 +++ python/CMakeLists.txt | 4 ++ python/aare/ClusterFinder.py | 14 ++++ python/aare/ClusterVector.py | 11 +++ python/aare/__init__.py | 4 ++ python/src/bind_ClusterVector.hpp | 103 +++++++++++++++++++++++++++++ python/src/cluster.hpp | 66 ------------------ python/src/module.cpp | 17 +++-- python/tests/test_Cluster.py | 59 +++++------------ python/tests/test_ClusterFile.py | 64 ++++++++++++++++++ python/tests/test_ClusterVector.py | 54 +++++++++++++++ src/CalculateEta.test.cpp | 70 +++++++++++++++++++- 13 files changed, 359 insertions(+), 117 deletions(-) create mode 100644 python/aare/ClusterFinder.py create mode 100644 python/aare/ClusterVector.py create mode 100644 python/src/bind_ClusterVector.hpp create mode 100644 python/tests/test_ClusterFile.py create mode 100644 python/tests/test_ClusterVector.py diff --git a/include/aare/ClusterFile.hpp b/include/aare/ClusterFile.hpp index 45df8a0..6ec2f2d 100644 --- a/include/aare/ClusterFile.hpp +++ b/include/aare/ClusterFile.hpp @@ -282,7 +282,7 @@ template ClusterVector ClusterFile::read_clusters_with_cut(size_t n_clusters) { ClusterVector clusters; - clusters.resize(n_clusters); + clusters.reserve(n_clusters); // if there are photons left from previous frame read them first if (m_num_left) { diff --git a/include/aare/ClusterVector.hpp b/include/aare/ClusterVector.hpp index 22315cc..e85a6f0 100644 --- a/include/aare/ClusterVector.hpp +++ b/include/aare/ClusterVector.hpp @@ -384,6 +384,14 @@ class ClusterVector> { void set_frame_number(uint64_t frame_number) { m_frame_number = frame_number; } + + std::vector sum() { + std::vector sums(m_data.size()); + for (size_t i = 0; i < m_data.size(); i++) { + sums[i] = m_data[i].sum(); + } + return sums; + } }; } // namespace aare \ No newline at end of file diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 09de736..9f54049 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -28,6 +28,9 @@ target_link_libraries(_aare PRIVATE aare_core aare_compiler_flags) set( PYTHON_FILES aare/__init__.py aare/CtbRawFile.py + aare/ClusterFinder.py + aare/ClusterVector.py + aare/func.py aare/RawFile.py aare/transform.py @@ -35,6 +38,7 @@ set( PYTHON_FILES aare/utils.py ) + # Copy the python files to the build directory foreach(FILE ${PYTHON_FILES}) configure_file(${FILE} ${CMAKE_BINARY_DIR}/${FILE} ) diff --git a/python/aare/ClusterFinder.py b/python/aare/ClusterFinder.py new file mode 100644 index 0000000..a2042a4 --- /dev/null +++ b/python/aare/ClusterFinder.py @@ -0,0 +1,14 @@ + +from ._aare import ClusterFinder_Cluster3x3i +import numpy as np + +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++. + """ + if dtype == np.int32 and cluster_size == (3,3): + return ClusterFinder_Cluster3x3i(image_size, n_sigma = n_sigma, capacity=capacity) + else: + #TODO! add the other formats + raise ValueError(f"Unsupported dtype: {dtype}. Only np.int32 is supported.") diff --git a/python/aare/ClusterVector.py b/python/aare/ClusterVector.py new file mode 100644 index 0000000..b0dd453 --- /dev/null +++ b/python/aare/ClusterVector.py @@ -0,0 +1,11 @@ + + +from ._aare import ClusterVector_Cluster3x3i +import numpy as np + +def ClusterVector(cluster_size, dtype = np.int32): + + if dtype == np.int32 and cluster_size == (3,3): + return ClusterVector_Cluster3x3i() + else: + raise ValueError(f"Unsupported dtype: {dtype}. Only np.int32 is supported.") diff --git a/python/aare/__init__.py b/python/aare/__init__.py index 8c51d73..b1eb604 100644 --- a/python/aare/__init__.py +++ b/python/aare/__init__.py @@ -11,8 +11,12 @@ from ._aare import ROI # from ._aare import ClusterFinderMT, ClusterCollector, ClusterFileSink, ClusterVector_i +from .ClusterFinder import ClusterFinder +from .ClusterVector import ClusterVector + from ._aare import fit_gaus, fit_pol1 from ._aare import Interpolator +from ._aare import calculate_eta2 from .CtbRawFile import CtbRawFile from .RawFile import RawFile from .ScanParameters import ScanParameters diff --git a/python/src/bind_ClusterVector.hpp b/python/src/bind_ClusterVector.hpp new file mode 100644 index 0000000..f7fa796 --- /dev/null +++ b/python/src/bind_ClusterVector.hpp @@ -0,0 +1,103 @@ +#include "aare/ClusterCollector.hpp" +#include "aare/ClusterFileSink.hpp" +#include "aare/ClusterFinder.hpp" +#include "aare/ClusterFinderMT.hpp" +#include "aare/ClusterVector.hpp" +#include "aare/NDView.hpp" +#include "aare/Pedestal.hpp" +#include "np_helper.hpp" + +#include +#include +#include +#include +#include + +namespace py = pybind11; +using pd_type = double; + +using namespace aare; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" + + +template +void define_ClusterVector(py::module &m, const std::string &typestr) { + using ClusterType = + Cluster; + auto class_name = fmt::format("ClusterVector_{}", typestr); + + py::class_, void>>( + m, class_name.c_str(), + py::buffer_protocol()) + + .def(py::init()) // TODO change!!! + + .def("push_back", + [](ClusterVector &self, const ClusterType &cluster) { + self.push_back(cluster); + }) + + .def("sum", [](ClusterVector &self) { + auto *vec = new std::vector(self.sum()); + return return_vector(vec); + }) + .def_property_readonly("size", &ClusterVector::size) + .def("item_size", &ClusterVector::item_size) + .def_property_readonly("fmt", + [typestr](ClusterVector &self) { + return fmt_format; + }) + + .def_property_readonly("cluster_size_x", + &ClusterVector::cluster_size_x) + .def_property_readonly("cluster_size_y", + &ClusterVector::cluster_size_y) + .def_property_readonly("capacity", + &ClusterVector::capacity) + .def_property("frame_number", &ClusterVector::frame_number, + &ClusterVector::set_frame_number) + .def_buffer( + [typestr](ClusterVector &self) -> py::buffer_info { + return py::buffer_info( + self.data(), /* Pointer to buffer */ + self.item_size(), /* Size of one scalar */ + fmt_format, /* Format descriptor */ + 1, /* Number of dimensions */ + {self.size()}, /* Buffer dimensions */ + {self.item_size()} /* Strides (in bytes) for each index */ + ); + }); + + // Free functions using ClusterVector + m.def("hitmap", + [](std::array image_size, ClusterVector &cv) { + + // Create a numpy array to hold the hitmap + // The shape of the array is (image_size[0], image_size[1]) + // note that the python array is passed as [row, col] which + // is the opposite of the clusters [x,y] + py::array_t hitmap(image_size); + auto r = hitmap.mutable_unchecked<2>(); + + // Initialize hitmap to 0 + for (py::ssize_t i = 0; i < r.shape(0); i++) + for (py::ssize_t j = 0; j < r.shape(1); j++) + r(i, j) = 0; + + + // Loop over the clusters and increment the hitmap + // Skip out of bound clusters + for (const auto& cluster : cv) { + auto x = cluster.x; + auto y = cluster.y; + if(x -void define_cluster_vector(py::module &m, const std::string &typestr) { - using ClusterType = - Cluster; - auto class_name = fmt::format("ClusterVector_{}", typestr); - py::class_, void>>( - m, class_name.c_str(), - py::buffer_protocol()) - - .def(py::init()) // TODO change!!! - - .def("push_back", - [](ClusterVector &self, const ClusterType &cluster) { - self.push_back(cluster); - }) - - // implement push_back - .def_property_readonly("size", &ClusterVector::size) - .def("item_size", &ClusterVector::item_size) - .def_property_readonly("fmt", - [typestr](ClusterVector &self) { - return fmt_format; - }) - - .def_property_readonly("cluster_size_x", - &ClusterVector::cluster_size_x) - .def_property_readonly("cluster_size_y", - &ClusterVector::cluster_size_y) - .def_property_readonly("capacity", - &ClusterVector::capacity) - .def_property("frame_number", &ClusterVector::frame_number, - &ClusterVector::set_frame_number) - .def_buffer( - [typestr](ClusterVector &self) -> py::buffer_info { - return py::buffer_info( - self.data(), /* Pointer to buffer */ - self.item_size(), /* Size of one scalar */ - fmt_format, /* Format descriptor */ - 1, /* Number of dimensions */ - {self.size()}, /* Buffer dimensions */ - {self.item_size()} /* Strides (in bytes) for each index */ - ); - }); -} template @@ -252,25 +206,5 @@ void define_cluster_finder_bindings(py::module &m, const std::string &typestr) { }, py::arg(), py::arg("frame_number") = 0); - m.def("hitmap", - [](std::array image_size, ClusterVector &cv) { - py::array_t hitmap(image_size); - auto r = hitmap.mutable_unchecked<2>(); - - // Initialize hitmap to 0 - for (py::ssize_t i = 0; i < r.shape(0); i++) - for (py::ssize_t j = 0; j < r.shape(1); j++) - r(i, j) = 0; - - size_t stride = cv.item_size(); - auto ptr = cv.data(); - for (size_t i = 0; i < cv.size(); i++) { - auto x = *reinterpret_cast(ptr); - auto y = *reinterpret_cast(ptr + sizeof(int16_t)); - r(y, x) += 1; - ptr += stride; - } - return hitmap; - }); } #pragma GCC diagnostic pop diff --git a/python/src/module.cpp b/python/src/module.cpp index 8d5b5ab..c2067ed 100644 --- a/python/src/module.cpp +++ b/python/src/module.cpp @@ -1,4 +1,9 @@ // Files with bindings to the different classes + +//New style file naming +#include "bind_ClusterVector.hpp" + +//TODO! migrate the other names #include "cluster.hpp" #include "cluster_file.hpp" #include "ctb_raw_file.hpp" @@ -39,12 +44,12 @@ PYBIND11_MODULE(_aare, m) { define_cluster_file_io_bindings(m, "Cluster2x2f"); define_cluster_file_io_bindings(m, "Cluster2x2d"); - define_cluster_vector(m, "Cluster3x3i"); - define_cluster_vector(m, "Cluster3x3d"); - define_cluster_vector(m, "Cluster3x3f"); - define_cluster_vector(m, "Cluster2x2i"); - define_cluster_vector(m, "Cluster2x2d"); - define_cluster_vector(m, "Cluster2x2f"); + define_ClusterVector(m, "Cluster3x3i"); + define_ClusterVector(m, "Cluster3x3d"); + define_ClusterVector(m, "Cluster3x3f"); + define_ClusterVector(m, "Cluster2x2i"); + define_ClusterVector(m, "Cluster2x2d"); + define_ClusterVector(m, "Cluster2x2f"); define_cluster_finder_bindings(m, "Cluster3x3i"); define_cluster_finder_bindings(m, "Cluster3x3d"); diff --git a/python/tests/test_Cluster.py b/python/tests/test_Cluster.py index e24bcf8..ddaa6f3 100644 --- a/python/tests/test_Cluster.py +++ b/python/tests/test_Cluster.py @@ -1,12 +1,12 @@ import pytest import numpy as np -import aare._aare as aare +from aare import _aare #import the C++ module from conftest import test_data_path def test_cluster_vector_can_be_converted_to_numpy(): - cv = aare.ClusterVector_Cluster3x3i() + cv = _aare.ClusterVector_Cluster3x3i() arr = np.array(cv, copy=False) assert arr.shape == (0,) # 4 for x, y, size, energy and 9 for the cluster data @@ -14,24 +14,23 @@ def test_cluster_vector_can_be_converted_to_numpy(): def test_ClusterVector(): """Test ClusterVector""" - clustervector = aare.ClusterVector_Cluster3x3i() + clustervector = _aare.ClusterVector_Cluster3x3i() assert clustervector.cluster_size_x == 3 assert clustervector.cluster_size_y == 3 assert clustervector.item_size() == 4+9*4 assert clustervector.frame_number == 0 - assert clustervector.capacity == 1024 assert clustervector.size == 0 - cluster = aare.Cluster3x3i(0,0,np.ones(9, dtype=np.int32)) + cluster = _aare.Cluster3x3i(0,0,np.ones(9, dtype=np.int32)) clustervector.push_back(cluster) assert clustervector.size == 1 with pytest.raises(TypeError): # Or use the appropriate exception type - clustervector.push_back(aare.Cluster2x2i(0,0,np.ones(4, dtype=np.int32))) + clustervector.push_back(_aare.Cluster2x2i(0,0,np.ones(4, dtype=np.int32))) with pytest.raises(TypeError): - clustervector.push_back(aare.Cluster3x3f(0,0,np.ones(9, dtype=np.float32))) + clustervector.push_back(_aare.Cluster3x3f(0,0,np.ones(9, dtype=np.float32))) def test_Interpolator(): """Test Interpolator""" @@ -41,13 +40,13 @@ def test_Interpolator(): ybins = np.linspace(0, 5, 30, dtype=np.float64) etacube = np.zeros(shape=[30, 30, 20], dtype=np.float64) - interpolator = aare.Interpolator(etacube, xbins, ybins, ebins) + interpolator = _aare.Interpolator(etacube, xbins, ybins, ebins) assert interpolator.get_ietax().shape == (30,30,20) assert interpolator.get_ietay().shape == (30,30,20) - clustervector = aare.ClusterVector_Cluster3x3i() + clustervector = _aare.ClusterVector_Cluster3x3i() - cluster = aare.Cluster3x3i(0,0, np.ones(9, dtype=np.int32)) + cluster = _aare.Cluster3x3i(0,0, np.ones(9, dtype=np.int32)) clustervector.push_back(cluster) interpolated_photons = interpolator.interpolate(clustervector) @@ -58,9 +57,9 @@ def test_Interpolator(): assert interpolated_photons[0]["y"] == -1 assert interpolated_photons[0]["energy"] == 4 #eta_sum = 4, dx, dy = -1,-1 m_ietax = 0, m_ietay = 0 - clustervector = aare.ClusterVector_Cluster2x2i() + clustervector = _aare.ClusterVector_Cluster2x2i() - cluster = aare.Cluster2x2i(0,0, np.ones(4, dtype=np.int32)) + cluster = _aare.Cluster2x2i(0,0, np.ones(4, dtype=np.int32)) clustervector.push_back(cluster) interpolated_photons = interpolator.interpolate(clustervector) @@ -71,28 +70,15 @@ def test_Interpolator(): assert interpolated_photons[0]["y"] == 0 assert interpolated_photons[0]["energy"] == 4 -@pytest.mark.files -def test_cluster_file(test_data_path): - """Test ClusterFile""" - cluster_file = aare.ClusterFile_Cluster3x3i(test_data_path / "clust/single_frame_97_clustrers.clust") - clustervector = cluster_file.read_clusters(10) #conversion does not work - cluster_file.close() - - assert clustervector.size == 10 - - ###reading with wrong file - with pytest.raises(TypeError): - cluster_file = aare.ClusterFile_Cluster2x2i(test_data_path / "clust/single_frame_97_clustrers.clust") - cluster_file.close() def test_calculate_eta(): """Calculate Eta""" - clusters = aare.ClusterVector_Cluster3x3i() - clusters.push_back(aare.Cluster3x3i(0,0, np.ones(9, dtype=np.int32))) - clusters.push_back(aare.Cluster3x3i(0,0, np.array([1,1,1,2,2,2,3,3,3]))) + clusters = _aare.ClusterVector_Cluster3x3i() + clusters.push_back(_aare.Cluster3x3i(0,0, np.ones(9, dtype=np.int32))) + clusters.push_back(_aare.Cluster3x3i(0,0, np.array([1,1,1,2,2,2,3,3,3]))) - eta2 = aare.calculate_eta2(clusters) + eta2 = _aare.calculate_eta2(clusters) assert eta2.shape == (2,2) assert eta2[0,0] == 0.5 @@ -103,7 +89,7 @@ def test_calculate_eta(): def test_cluster_finder(): """Test ClusterFinder""" - clusterfinder = aare.ClusterFinder_Cluster3x3i([100,100]) + clusterfinder = _aare.ClusterFinder_Cluster3x3i([100,100]) #frame = np.random.rand(100,100) frame = np.zeros(shape=[100,100]) @@ -115,18 +101,7 @@ def test_cluster_finder(): assert clusters.size == 0 -#TODO dont understand behavior -def test_cluster_collector(): - """Test ClusterCollector""" - - clusterfinder = aare.ClusterFinderMT_Cluster3x3i([100,100]) #TODO: no idea what the data is in InputQueue not zero - - clustercollector = aare.ClusterCollector_Cluster3x3i(clusterfinder) - - cluster_vectors = clustercollector.steal_clusters() - - assert len(cluster_vectors) == 1 #single thread execution - assert cluster_vectors[0].size == 0 # + diff --git a/python/tests/test_ClusterFile.py b/python/tests/test_ClusterFile.py new file mode 100644 index 0000000..4126a6c --- /dev/null +++ b/python/tests/test_ClusterFile.py @@ -0,0 +1,64 @@ + +import pytest +import numpy as np +import boost_histogram as bh +import time +from pathlib import Path +import pickle + +from aare import ClusterFile +from conftest import test_data_path + +@pytest.mark.files +def test_cluster_file(test_data_path): + """Test ClusterFile""" + f = ClusterFile(test_data_path / "clust/single_frame_97_clustrers.clust") + cv = f.read_clusters(10) #conversion does not work + + + assert cv.frame_number == 135 + assert cv.size == 10 + + #Known data + #frame_number, num_clusters [135] 97 + #[ 1 200] [0 1 2 3 4 5 6 7 8] + #[ 2 201] [ 9 10 11 12 13 14 15 16 17] + #[ 3 202] [18 19 20 21 22 23 24 25 26] + #[ 4 203] [27 28 29 30 31 32 33 34 35] + #[ 5 204] [36 37 38 39 40 41 42 43 44] + #[ 6 205] [45 46 47 48 49 50 51 52 53] + #[ 7 206] [54 55 56 57 58 59 60 61 62] + #[ 8 207] [63 64 65 66 67 68 69 70 71] + #[ 9 208] [72 73 74 75 76 77 78 79 80] + #[ 10 209] [81 82 83 84 85 86 87 88 89] + + #conversion to numpy array + arr = np.array(cv, copy = False) + + assert arr.size == 10 + for i in range(10): + assert arr[i]['x'] == i+1 + +@pytest.mark.files +def test_read_clusters_and_fill_histogram(test_data_path): + # Create the histogram + n_bins = 100 + xmin = -100 + xmax = 1e4 + hist_aare = bh.Histogram(bh.axis.Regular(n_bins, xmin, xmax)) + + fname = test_data_path / "clust/beam_En700eV_-40deg_300V_10us_d0_f0_100.clust" + + #Read clusters and fill the histogram with pixel values + with ClusterFile(fname, chunk_size = 10000) as f: + for clusters in f: + arr = np.array(clusters, copy = False) + hist_aare.fill(arr['data'].flat) + + + #Load the histogram from the pickle file + with open(fname.with_suffix('.pkl'), 'rb') as f: + hist_py = pickle.load(f) + + #Compare the two histograms + assert hist_aare == hist_py \ No newline at end of file diff --git a/python/tests/test_ClusterVector.py b/python/tests/test_ClusterVector.py new file mode 100644 index 0000000..b64aeef --- /dev/null +++ b/python/tests/test_ClusterVector.py @@ -0,0 +1,54 @@ +import pytest +import numpy as np +import boost_histogram as bh +import time +from pathlib import Path +import pickle + +from aare import ClusterFile +from aare import _aare +from conftest import test_data_path + + +def test_create_cluster_vector(): + cv = _aare.ClusterVector_Cluster3x3i() + assert cv.cluster_size_x == 3 + assert cv.cluster_size_y == 3 + assert cv.size == 0 + + +def test_push_back_on_cluster_vector(): + cv = _aare.ClusterVector_Cluster2x2i() + assert cv.cluster_size_x == 2 + assert cv.cluster_size_y == 2 + assert cv.size == 0 + + cluster = _aare.Cluster2x2i(19, 22, np.ones(4, dtype=np.int32)) + cv.push_back(cluster) + assert cv.size == 1 + + arr = np.array(cv, copy=False) + assert arr[0]['x'] == 19 + assert arr[0]['y'] == 22 + + +def test_make_a_hitmap_from_cluster_vector(): + cv = _aare.ClusterVector_Cluster3x3i() + + # Push back 4 clusters with different positions + cv.push_back(_aare.Cluster3x3i(0, 0, np.ones(9, dtype=np.int32))) + cv.push_back(_aare.Cluster3x3i(1, 1, np.ones(9, dtype=np.int32))) + cv.push_back(_aare.Cluster3x3i(1, 1, np.ones(9, dtype=np.int32))) + cv.push_back(_aare.Cluster3x3i(2, 2, np.ones(9, dtype=np.int32))) + + ref = np.zeros((5, 5), dtype=np.int32) + ref[0,0] = 1 + ref[1,1] = 2 + ref[2,2] = 1 + + + img = _aare.hitmap((5,5), cv) + # print(img) + # print(ref) + assert (img == ref).all() + \ No newline at end of file diff --git a/src/CalculateEta.test.cpp b/src/CalculateEta.test.cpp index 2bdf387..29d7ed3 100644 --- a/src/CalculateEta.test.cpp +++ b/src/CalculateEta.test.cpp @@ -37,7 +37,7 @@ auto get_test_parameters() { Eta2{3. / 5, 4. / 6, 1, 11})); } -TEST_CASE("compute_largest_2x2_subcluster", "[.eta_calculation]") { +TEST_CASE("compute_largest_2x2_subcluster", "[eta_calculation]") { auto [cluster, expected_eta] = get_test_parameters(); auto [sum, index] = std::visit( @@ -47,7 +47,7 @@ TEST_CASE("compute_largest_2x2_subcluster", "[.eta_calculation]") { CHECK(expected_eta.sum == sum); } -TEST_CASE("calculate_eta2", "[.eta_calculation]") { +TEST_CASE("calculate_eta2", "[eta_calculation]") { auto [cluster, expected_eta] = get_test_parameters(); @@ -60,3 +60,69 @@ TEST_CASE("calculate_eta2", "[.eta_calculation]") { CHECK(eta.c == expected_eta.c); CHECK(eta.sum == expected_eta.sum); } + + +//3x3 cluster layout (in case of cBottomLeft etc corner): +// 6, 7, 8 +// 3, 4, 5 +// 0, 1, 2 + + +TEST_CASE("Calculate eta2 for a 3x3 int32 cluster with the largest 2x2 sum in the bottom left", + "[eta_calculation]") { + + // Create a 3x3 cluster + Cluster cl; + cl.x = 0; + cl.y = 0; + cl.data[0] = 30; + cl.data[1] = 23; + cl.data[2] = 5; + cl.data[3] = 20; + cl.data[4] = 50; + cl.data[5] = 3; + cl.data[6] = 8; + cl.data[7] = 2; + cl.data[8] = 3; + + // 8, 2, 3 + // 20, 50, 3 + // 30, 23, 5 + + auto eta = calculate_eta2(cl); + CHECK(eta.c == corner::cBottomLeft); + CHECK(eta.x == 50.0 / (20 + 50)); // 4/(3+4) + CHECK(eta.y == 50.0 / (23 + 50)); // 4/(1+4) + CHECK(eta.sum == 30+23+20+50); + +} + +TEST_CASE("Calculate eta2 for a 3x3 int32 cluster with the largest 2x2 sum in the top left", + "[eta_calculation]") { + +// Create a 3x3 cluster +Cluster cl; +cl.x = 0; +cl.y = 0; +cl.data[0] = 8; +cl.data[1] = 12; +cl.data[2] = 5; +cl.data[3] = 77; +cl.data[4] = 80; +cl.data[5] = 3; +cl.data[6] = 82; +cl.data[7] = 91; +cl.data[8] = 3; + +// 82, 91, 3 +// 77, 80, 3 +// 8, 12, 5 + +auto eta = calculate_eta2(cl); +CHECK(eta.c == corner::cTopLeft); +CHECK(eta.x == 80. / (77 + 80)); // 4/(3+4) +CHECK(eta.y == 91.0 / (91 + 80)); // 7/(7+4) +CHECK(eta.sum == 77+80+82+91); + +} + From 5f34ab6df143d3420c0e934c159b11a53b336a48 Mon Sep 17 00:00:00 2001 From: froejdh_e Date: Tue, 15 Apr 2025 08:05:05 +0200 Subject: [PATCH 39/51] minor comment --- src/CalculateEta.test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CalculateEta.test.cpp b/src/CalculateEta.test.cpp index 29d7ed3..59a616e 100644 --- a/src/CalculateEta.test.cpp +++ b/src/CalculateEta.test.cpp @@ -62,7 +62,7 @@ TEST_CASE("calculate_eta2", "[eta_calculation]") { } -//3x3 cluster layout (in case of cBottomLeft etc corner): +//3x3 cluster layout (rotated to match the cBottomLeft enum): // 6, 7, 8 // 3, 4, 5 // 0, 1, 2 From a90e532b21b56a810eaff3958084f4fbe548846f Mon Sep 17 00:00:00 2001 From: froejdh_e Date: Tue, 15 Apr 2025 08:08:59 +0200 Subject: [PATCH 40/51] removed extra sum after merge --- include/aare/ClusterVector.hpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/include/aare/ClusterVector.hpp b/include/aare/ClusterVector.hpp index 3084c96..cc88256 100644 --- a/include/aare/ClusterVector.hpp +++ b/include/aare/ClusterVector.hpp @@ -162,14 +162,6 @@ class ClusterVector> { void set_frame_number(int32_t frame_number) { m_frame_number = frame_number; } - - std::vector sum() { - std::vector sums(m_data.size()); - for (size_t i = 0; i < m_data.size(); i++) { - sums[i] = m_data[i].sum(); - } - return sums; - } }; } // namespace aare \ No newline at end of file From 1174f7f43472d19fd6d473678265ac688cf5d203 Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Tue, 15 Apr 2025 13:14:07 +0200 Subject: [PATCH 41/51] fixed calculate eta --- include/aare/CalculateEta.hpp | 77 +++++++++++++++++++++++++++------- include/aare/ClusterVector.hpp | 2 +- src/CalculateEta.test.cpp | 8 ++-- 3 files changed, 67 insertions(+), 20 deletions(-) diff --git a/include/aare/CalculateEta.hpp b/include/aare/CalculateEta.hpp index 2797233..1566de5 100644 --- a/include/aare/CalculateEta.hpp +++ b/include/aare/CalculateEta.hpp @@ -64,31 +64,78 @@ calculate_eta2(const Cluster &cl) { eta.sum = max_sum.first; auto c = max_sum.second; + size_t cluster_center_index = + (ClusterSizeX / 2) + (ClusterSizeY / 2) * ClusterSizeX; + size_t index_bottom_left_max_2x2_subcluster = (int(c / (ClusterSizeX - 1))) * ClusterSizeX + c % (ClusterSizeX - 1); - if ((cl.data[index_bottom_left_max_2x2_subcluster] + - cl.data[index_bottom_left_max_2x2_subcluster + 1]) != 0) - eta.x = static_cast( - cl.data[index_bottom_left_max_2x2_subcluster + 1]) / - static_cast( - (cl.data[index_bottom_left_max_2x2_subcluster] + - cl.data[index_bottom_left_max_2x2_subcluster + 1])); + // 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 && + cluster_center_index != + index_bottom_left_max_2x2_subcluster + ClusterSizeX && + cluster_center_index != + index_bottom_left_max_2x2_subcluster + ClusterSizeX + 1) + throw std::runtime_error("Photon center is not in max 2x2_subcluster"); - if ((cl.data[index_bottom_left_max_2x2_subcluster] + - cl.data[index_bottom_left_max_2x2_subcluster + ClusterSizeX]) != 0) - eta.y = - static_cast( - cl.data[index_bottom_left_max_2x2_subcluster + ClusterSizeX]) / - static_cast( - (cl.data[index_bottom_left_max_2x2_subcluster] + - cl.data[index_bottom_left_max_2x2_subcluster + ClusterSizeX])); + if ((cluster_center_index - index_bottom_left_max_2x2_subcluster) % + ClusterSizeX == + 0) { + if ((cl.data[cluster_center_index + 1] + + cl.data[cluster_center_index]) != 0) + + eta.x = static_cast(cl.data[cluster_center_index + 1]) / + static_cast((cl.data[cluster_center_index + 1] + + cl.data[cluster_center_index])); + } else { + if ((cl.data[cluster_center_index] + + cl.data[cluster_center_index - 1]) != 0) + + eta.x = static_cast(cl.data[cluster_center_index]) / + static_cast((cl.data[cluster_center_index - 1] + + cl.data[cluster_center_index])); + } + if ((cluster_center_index - index_bottom_left_max_2x2_subcluster) / + ClusterSizeX < + 1) { + assert(cluster_center_index + ClusterSizeX < + ClusterSizeX * ClusterSizeY); // suppress warning + if ((cl.data[cluster_center_index] + + cl.data[cluster_center_index + ClusterSizeX]) != 0) + eta.y = static_cast( + cl.data[cluster_center_index + ClusterSizeX]) / + static_cast( + (cl.data[cluster_center_index] + + cl.data[cluster_center_index + ClusterSizeX])); + } else { + if ((cl.data[cluster_center_index] + + cl.data[cluster_center_index - ClusterSizeX]) != 0) + eta.y = static_cast(cl.data[cluster_center_index]) / + static_cast( + (cl.data[cluster_center_index] + + cl.data[cluster_center_index - ClusterSizeX])); + } eta.c = c; // TODO only supported for 2x2 and 3x3 clusters -> at least no // underyling enum class return eta; } +// Dont get why this is correct - photon center should be top right corner +template +Eta2 calculate_eta2(const Cluster &cl) { + Eta2 eta{}; + + if ((cl.data[0] + cl.data[1]) != 0) + eta.x = static_cast(cl.data[1]) / (cl.data[0] + cl.data[1]); + if ((cl.data[0] + cl.data[2]) != 0) + eta.y = static_cast(cl.data[2]) / (cl.data[0] + cl.data[2]); + eta.sum = cl.sum(); + eta.c = cBottomLeft; // TODO! This is not correct, but need to put something + return eta; +} + // calculates Eta3 for 3x3 cluster based on code from analyze_cluster // TODO only supported for 3x3 Clusters template Eta2 calculate_eta3(const Cluster &cl) { diff --git a/include/aare/ClusterVector.hpp b/include/aare/ClusterVector.hpp index cc88256..e91cb6d 100644 --- a/include/aare/ClusterVector.hpp +++ b/include/aare/ClusterVector.hpp @@ -47,7 +47,7 @@ class ClusterVector> { * @param frame_number frame number of the clusters. Default is 0, which is * also used to indicate that the clusters come from many frames */ - ClusterVector(size_t capacity = 300, uint64_t frame_number = 0) + ClusterVector(size_t capacity = 1024, uint64_t frame_number = 0) : m_frame_number(frame_number) { m_data.reserve(capacity); } diff --git a/src/CalculateEta.test.cpp b/src/CalculateEta.test.cpp index 59a616e..cdec79b 100644 --- a/src/CalculateEta.test.cpp +++ b/src/CalculateEta.test.cpp @@ -26,15 +26,15 @@ auto get_test_parameters() { ClusterTypes{Cluster{0, 0, {1, 2, 3, 4, 5, 6, 1, 2, 7}}}, Eta2{6. / 11, 2. / 7, corner::cTopRight, 20}), std::make_tuple(ClusterTypes{Cluster{ - 0, 0, {1, 6, 7, 6, 5, 4, 3, 2, 1, 8, 8, 9, 2, + 0, 0, {1, 6, 7, 6, 5, 4, 3, 2, 1, 2, 8, 9, 8, 1, 4, 5, 6, 7, 8, 4, 1, 1, 1, 1, 1}}}, - Eta2{9. / 17, 5. / 13, 8, 28}), + Eta2{8. / 17, 7. / 15, 9, 30}), std::make_tuple( ClusterTypes{Cluster{0, 0, {1, 4, 7, 2, 5, 6, 4, 3}}}, - Eta2{7. / 11, 6. / 10, 1, 21}), + Eta2{4. / 10, 4. / 11, 1, 21}), std::make_tuple( ClusterTypes{Cluster{0, 0, {1, 3, 2, 3, 4, 2}}}, - Eta2{3. / 5, 4. / 6, 1, 11})); + Eta2{3. / 5, 2. / 5, 1, 11})); } TEST_CASE("compute_largest_2x2_subcluster", "[eta_calculation]") { From fca9d5d2fa328e8952d27f24e16f73120b5bccf7 Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Tue, 15 Apr 2025 14:40:09 +0200 Subject: [PATCH 42/51] replaced extract template parameters --- include/aare/Cluster.hpp | 30 ++++++++++++++---------------- include/aare/ClusterFile.hpp | 8 ++------ include/aare/ClusterFinder.hpp | 8 +++----- include/aare/ClusterFinderMT.hpp | 2 +- 4 files changed, 20 insertions(+), 28 deletions(-) diff --git a/include/aare/Cluster.hpp b/include/aare/Cluster.hpp index a2c9b55..7eb1a13 100644 --- a/include/aare/Cluster.hpp +++ b/include/aare/Cluster.hpp @@ -32,6 +32,11 @@ struct Cluster { CoordType y; T data[ClusterSizeX * ClusterSizeY]; + static constexpr uint8_t cluster_size_x = ClusterSizeX; + static constexpr uint8_t cluster_size_y = ClusterSizeY; + using value_type = T; + using coord_type = CoordType; + T sum() const { return std::accumulate(data, data + ClusterSizeX * ClusterSizeY, 0); } @@ -64,6 +69,11 @@ template struct Cluster { int16_t y; T data[4]; + static constexpr uint8_t cluster_size_x = 2; + static constexpr uint8_t cluster_size_y = 2; + using value_type = T; + using coord_type = int16_t; + T sum() const { return std::accumulate(data, data + 4, 0); } std::pair max_sum_2x2() const { @@ -77,6 +87,10 @@ template struct Cluster { int16_t x; int16_t y; T data[9]; + static constexpr uint8_t cluster_size_x = 3; + static constexpr uint8_t cluster_size_y = 3; + using value_type = T; + using coord_type = int16_t; T sum() const { return std::accumulate(data, data + 9, 0); } @@ -102,20 +116,4 @@ struct is_cluster> : std::true_type {}; // Cluster template constexpr bool is_cluster_v = is_cluster::value; -template >> -struct extract_template_arguments; // Forward declaration - -// helper struct to extract template argument -template -struct extract_template_arguments< - Cluster> { - - using value_type = T; - static constexpr int cluster_size_x = ClusterSizeX; - static constexpr int cluster_size_y = ClusterSizeY; - using coordtype = CoordType; -}; - } // namespace aare diff --git a/include/aare/ClusterFile.hpp b/include/aare/ClusterFile.hpp index 06de985..b063008 100644 --- a/include/aare/ClusterFile.hpp +++ b/include/aare/ClusterFile.hpp @@ -465,13 +465,9 @@ bool ClusterFile::is_selected(ClusterType &cl) { } } - auto cluster_size_x = extract_template_arguments< - std::remove_reference_t>::cluster_size_x; - auto cluster_size_y = extract_template_arguments< - std::remove_reference_t>::cluster_size_y; - size_t cluster_center_index = - (cluster_size_x / 2) + (cluster_size_y / 2) * cluster_size_x; + (ClusterType::cluster_size_x / 2) + + (ClusterType::cluster_size_y / 2) * ClusterType::cluster_size_x; if (m_noise_map) { auto sum_1x1 = cl.data[cluster_center_index]; // central pixel diff --git a/include/aare/ClusterFinder.hpp b/include/aare/ClusterFinder.hpp index 8c3540a..b3538eb 100644 --- a/include/aare/ClusterFinder.hpp +++ b/include/aare/ClusterFinder.hpp @@ -20,11 +20,9 @@ class ClusterFinder { Pedestal m_pedestal; ClusterVector m_clusters; - static const uint8_t ClusterSizeX = - extract_template_arguments::cluster_size_x; - static const uint8_t ClusterSizeY = - extract_template_arguments::cluster_size_x; - using CT = typename extract_template_arguments::value_type; + 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: /** diff --git a/include/aare/ClusterFinderMT.hpp b/include/aare/ClusterFinderMT.hpp index 75b6497..29fc715 100644 --- a/include/aare/ClusterFinderMT.hpp +++ b/include/aare/ClusterFinderMT.hpp @@ -34,7 +34,7 @@ template , typename FRAME_TYPE = uint16_t, typename PEDESTAL_TYPE = double> class ClusterFinderMT { - using CT = typename extract_template_arguments::value_type; + using CT = typename ClusterType::value_type; size_t m_current_thread{0}; size_t m_n_threads{0}; using Finder = ClusterFinder; From d4050ec557a870b17f9e2ef0bcde912f321d9d43 Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Tue, 15 Apr 2025 14:57:25 +0200 Subject: [PATCH 43/51] enum is now enum class --- include/aare/CalculateEta.hpp | 11 ++--- include/aare/Interpolator.hpp | 10 ++--- src/CalculateEta.test.cpp | 75 +++++++++++++++++------------------ 3 files changed, 48 insertions(+), 48 deletions(-) diff --git a/include/aare/CalculateEta.hpp b/include/aare/CalculateEta.hpp index 1566de5..289e8bc 100644 --- a/include/aare/CalculateEta.hpp +++ b/include/aare/CalculateEta.hpp @@ -6,14 +6,14 @@ namespace aare { -typedef enum { +enum class corner : int { cBottomLeft = 0, cBottomRight = 1, cTopLeft = 2, cTopRight = 3 -} corner; +}; -typedef enum { +enum class pixel : int { pBottomLeft = 0, pBottom = 1, pBottomRight = 2, @@ -23,7 +23,7 @@ typedef enum { pTopLeft = 6, pTop = 7, pTopRight = 8 -} pixel; +}; template struct Eta2 { double x; @@ -132,7 +132,8 @@ Eta2 calculate_eta2(const Cluster &cl) { if ((cl.data[0] + cl.data[2]) != 0) eta.y = static_cast(cl.data[2]) / (cl.data[0] + cl.data[2]); eta.sum = cl.sum(); - eta.c = cBottomLeft; // TODO! This is not correct, but need to put something + eta.c = static_cast(corner::cBottomLeft); // TODO! This is not correct, + // but need to put something return eta; } diff --git a/include/aare/Interpolator.hpp b/include/aare/Interpolator.hpp index 7e3a1c1..85ccf29 100644 --- a/include/aare/Interpolator.hpp +++ b/include/aare/Interpolator.hpp @@ -70,20 +70,20 @@ Interpolator::interpolate(const ClusterVector &clusters) { // cBottomRight = 1, // cTopLeft = 2, // cTopRight = 3 - switch (eta.c) { - case cTopLeft: + switch (static_cast(eta.c)) { + case corner::cTopLeft: dX = -1.; dY = 0; break; - case cTopRight:; + case corner::cTopRight:; dX = 0; dY = 0; break; - case cBottomLeft: + case corner::cBottomLeft: dX = -1.; dY = -1.; break; - case cBottomRight: + case corner::cBottomRight: dX = 0.; dY = -1.; break; diff --git a/src/CalculateEta.test.cpp b/src/CalculateEta.test.cpp index cdec79b..820ab44 100644 --- a/src/CalculateEta.test.cpp +++ b/src/CalculateEta.test.cpp @@ -21,10 +21,12 @@ using ClusterTypes = auto get_test_parameters() { return GENERATE( std::make_tuple(ClusterTypes{Cluster{0, 0, {1, 2, 3, 1}}}, - Eta2{2. / 3, 3. / 4, corner::cBottomLeft, 7}), + Eta2{2. / 3, 3. / 4, + static_cast(corner::cBottomLeft), 7}), std::make_tuple( ClusterTypes{Cluster{0, 0, {1, 2, 3, 4, 5, 6, 1, 2, 7}}}, - Eta2{6. / 11, 2. / 7, corner::cTopRight, 20}), + Eta2{6. / 11, 2. / 7, static_cast(corner::cTopRight), + 20}), std::make_tuple(ClusterTypes{Cluster{ 0, 0, {1, 6, 7, 6, 5, 4, 3, 2, 1, 2, 8, 9, 8, 1, 4, 5, 6, 7, 8, 4, 1, 1, 1, 1, 1}}}, @@ -61,14 +63,13 @@ TEST_CASE("calculate_eta2", "[eta_calculation]") { CHECK(eta.sum == expected_eta.sum); } +// 3x3 cluster layout (rotated to match the cBottomLeft enum): +// 6, 7, 8 +// 3, 4, 5 +// 0, 1, 2 -//3x3 cluster layout (rotated to match the cBottomLeft enum): -// 6, 7, 8 -// 3, 4, 5 -// 0, 1, 2 - - -TEST_CASE("Calculate eta2 for a 3x3 int32 cluster with the largest 2x2 sum in the bottom left", +TEST_CASE("Calculate eta2 for a 3x3 int32 cluster with the largest 2x2 sum in " + "the bottom left", "[eta_calculation]") { // Create a 3x3 cluster @@ -84,45 +85,43 @@ TEST_CASE("Calculate eta2 for a 3x3 int32 cluster with the largest 2x2 sum in th cl.data[6] = 8; cl.data[7] = 2; cl.data[8] = 3; - + // 8, 2, 3 // 20, 50, 3 // 30, 23, 5 auto eta = calculate_eta2(cl); - CHECK(eta.c == corner::cBottomLeft); + CHECK(eta.c == static_cast(corner::cBottomLeft)); CHECK(eta.x == 50.0 / (20 + 50)); // 4/(3+4) CHECK(eta.y == 50.0 / (23 + 50)); // 4/(1+4) - CHECK(eta.sum == 30+23+20+50); - + CHECK(eta.sum == 30 + 23 + 20 + 50); } -TEST_CASE("Calculate eta2 for a 3x3 int32 cluster with the largest 2x2 sum in the top left", - "[eta_calculation]") { +TEST_CASE("Calculate eta2 for a 3x3 int32 cluster with the largest 2x2 sum in " + "the top left", + "[eta_calculation]") { -// Create a 3x3 cluster -Cluster cl; -cl.x = 0; -cl.y = 0; -cl.data[0] = 8; -cl.data[1] = 12; -cl.data[2] = 5; -cl.data[3] = 77; -cl.data[4] = 80; -cl.data[5] = 3; -cl.data[6] = 82; -cl.data[7] = 91; -cl.data[8] = 3; + // Create a 3x3 cluster + Cluster cl; + cl.x = 0; + cl.y = 0; + cl.data[0] = 8; + cl.data[1] = 12; + cl.data[2] = 5; + cl.data[3] = 77; + cl.data[4] = 80; + cl.data[5] = 3; + cl.data[6] = 82; + cl.data[7] = 91; + cl.data[8] = 3; -// 82, 91, 3 -// 77, 80, 3 -// 8, 12, 5 - -auto eta = calculate_eta2(cl); -CHECK(eta.c == corner::cTopLeft); -CHECK(eta.x == 80. / (77 + 80)); // 4/(3+4) -CHECK(eta.y == 91.0 / (91 + 80)); // 7/(7+4) -CHECK(eta.sum == 77+80+82+91); + // 82, 91, 3 + // 77, 80, 3 + // 8, 12, 5 + auto eta = calculate_eta2(cl); + CHECK(eta.c == static_cast(corner::cTopLeft)); + CHECK(eta.x == 80. / (77 + 80)); // 4/(3+4) + CHECK(eta.y == 91.0 / (91 + 80)); // 7/(7+4) + CHECK(eta.sum == 77 + 80 + 82 + 91); } - From acd9d5d4876a5b43c2f62cbf41eed71666f74d2d Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Tue, 15 Apr 2025 15:15:34 +0200 Subject: [PATCH 44/51] moved parts of ClusterFile implementation into declaration --- include/aare/ClusterFile.hpp | 301 +++++++++++++++-------------------- 1 file changed, 129 insertions(+), 172 deletions(-) diff --git a/include/aare/ClusterFile.hpp b/include/aare/ClusterFile.hpp index b063008..ab6488a 100644 --- a/include/aare/ClusterFile.hpp +++ b/include/aare/ClusterFile.hpp @@ -60,26 +60,81 @@ class ClusterFile { * @throws std::runtime_error if the file could not be opened */ ClusterFile(const std::filesystem::path &fname, size_t chunk_size = 1000, - const std::string &mode = "r"); + const std::string &mode = "r") - ~ClusterFile(); + : m_filename(fname.string()), m_chunk_size(chunk_size), m_mode(mode) { + + if (mode == "r") { + fp = fopen(m_filename.c_str(), "rb"); + if (!fp) { + throw std::runtime_error("Could not open file for reading: " + + m_filename); + } + } else if (mode == "w") { + fp = fopen(m_filename.c_str(), "wb"); + if (!fp) { + throw std::runtime_error("Could not open file for writing: " + + m_filename); + } + } else if (mode == "a") { + fp = fopen(m_filename.c_str(), "ab"); + if (!fp) { + throw std::runtime_error("Could not open file for appending: " + + m_filename); + } + } else { + throw std::runtime_error("Unsupported mode: " + mode); + } + } + + ~ClusterFile() { close(); } /** - * @brief Read n_clusters clusters from the file discarding frame numbers. - * If EOF is reached the returned vector will have less than n_clusters - * clusters + * @brief Read n_clusters clusters from the file discarding + * frame numbers. If EOF is reached the returned vector will + * have less than n_clusters clusters */ - ClusterVector read_clusters(size_t n_clusters); + ClusterVector read_clusters(size_t n_clusters) { + if (m_mode != "r") { + throw std::runtime_error("File not opened for reading"); + } + if (m_noise_map || m_roi) { + return read_clusters_with_cut(n_clusters); + } else { + return read_clusters_without_cut(n_clusters); + } + } /** - * @brief Read a single frame from the file and return the clusters. The - * cluster vector will have the frame number set. - * @throws std::runtime_error if the file is not opened for reading or the - * file pointer not at the beginning of a frame + * @brief Read a single frame from the file and return the + * clusters. The cluster vector will have the frame number + * set. + * @throws std::runtime_error if the file is not opened for + * reading or the file pointer not at the beginning of a + * frame */ - ClusterVector read_frame(); + ClusterVector read_frame() { + if (m_mode != "r") { + throw std::runtime_error(LOCATION + "File not opened for reading"); + } + if (m_noise_map || m_roi) { + return read_frame_with_cut(); + } else { + return read_frame_without_cut(); + } + } - void write_frame(const ClusterVector &clusters); + void write_frame(const ClusterVector &clusters) { + if (m_mode != "w" && m_mode != "a") { + throw std::runtime_error("File not opened for writing"); + } + + int32_t frame_number = clusters.frame_number(); + fwrite(&frame_number, sizeof(frame_number), 1, fp); + uint32_t n_clusters = clusters.size(); + fwrite(&n_clusters, sizeof(n_clusters), 1, fp); + fwrite(clusters.data(), clusters.item_size(), clusters.size(), fp); + } /** * @brief Return the chunk size @@ -87,39 +142,80 @@ class ClusterFile { size_t chunk_size() const { return m_chunk_size; } /** - * @brief Set the region of interest to use when reading clusters. If set - * only clusters within the ROI will be read. + * @brief Set the region of interest to use when reading + * clusters. If set only clusters within the ROI will be + * read. */ - void set_roi(ROI roi); + void set_roi(ROI roi) { m_roi = roi; } /** - * @brief Set the noise map to use when reading clusters. If set clusters - * below the noise level will be discarded. Selection criteria one of: - * Central pixel above noise, highest 2x2 sum above 2 * noise, total sum - * above 3 * noise. + * @brief Set the noise map to use when reading clusters. If + * set clusters below the noise level will be discarded. + * Selection criteria one of: Central pixel above noise, + * highest 2x2 sum above 2 * noise, total sum above 3 * + * noise. */ - void set_noise_map(const NDView noise_map); + void set_noise_map(const NDView noise_map) { + m_noise_map = NDArray(noise_map); + } /** - * @brief Set the gain map to use when reading clusters. If set the gain map - * will be applied to the clusters that pass ROI and noise_map selection. + * @brief Set the gain map to use when reading clusters. If + * set the gain map will be applied to the clusters that + * pass ROI and noise_map selection. */ - void set_gain_map(const NDView gain_map); + void set_gain_map(const NDView gain_map) { + m_gain_map = GainMap(gain_map); + } - void set_gain_map(const GainMap &gain_map); + void set_gain_map(const GainMap &gain_map) { m_gain_map = gain_map; } - void set_gain_map(const GainMap &&gain_map); + void set_gain_map(const GainMap &&gain_map) { m_gain_map = gain_map; } /** - * @brief Close the file. If not closed the file will be closed in the - * destructor + * @brief Close the file. If not closed the file will be + * closed in the destructor */ - void close(); + void close() { + if (fp) { + fclose(fp); + fp = nullptr; + } + } /** @brief Open the file in specific mode * */ - void open(const std::string &mode); + void open(const std::string &mode) { + if (fp) { + close(); + } + + if (mode == "r") { + fp = fopen(m_filename.c_str(), "rb"); + if (!fp) { + throw std::runtime_error("Could not open file for reading: " + + m_filename); + } + m_mode = "r"; + } else if (mode == "w") { + fp = fopen(m_filename.c_str(), "wb"); + if (!fp) { + throw std::runtime_error("Could not open file for writing: " + + m_filename); + } + m_mode = "w"; + } else if (mode == "a") { + fp = fopen(m_filename.c_str(), "ab"); + if (!fp) { + throw std::runtime_error("Could not open file for appending: " + + m_filename); + } + m_mode = "a"; + } else { + throw std::runtime_error("Unsupported mode: " + mode); + } + } private: ClusterVector read_clusters_with_cut(size_t n_clusters); @@ -130,133 +226,6 @@ class ClusterFile { ClusterType read_one_cluster(); }; -template -ClusterFile::ClusterFile( - const std::filesystem::path &fname, size_t chunk_size, - const std::string &mode) - : m_filename(fname.string()), m_chunk_size(chunk_size), m_mode(mode) { - - if (mode == "r") { - fp = fopen(m_filename.c_str(), "rb"); - if (!fp) { - throw std::runtime_error("Could not open file for reading: " + - m_filename); - } - } else if (mode == "w") { - fp = fopen(m_filename.c_str(), "wb"); - if (!fp) { - throw std::runtime_error("Could not open file for writing: " + - m_filename); - } - } else if (mode == "a") { - fp = fopen(m_filename.c_str(), "ab"); - if (!fp) { - throw std::runtime_error("Could not open file for appending: " + - m_filename); - } - } else { - throw std::runtime_error("Unsupported mode: " + mode); - } -} - -template -ClusterFile::~ClusterFile() { - close(); -} - -template -void ClusterFile::close() { - if (fp) { - fclose(fp); - fp = nullptr; - } -} - -template -void ClusterFile::open(const std::string &mode) { - if (fp) { - close(); - } - - if (mode == "r") { - fp = fopen(m_filename.c_str(), "rb"); - if (!fp) { - throw std::runtime_error("Could not open file for reading: " + - m_filename); - } - m_mode = "r"; - } else if (mode == "w") { - fp = fopen(m_filename.c_str(), "wb"); - if (!fp) { - throw std::runtime_error("Could not open file for writing: " + - m_filename); - } - m_mode = "w"; - } else if (mode == "a") { - fp = fopen(m_filename.c_str(), "ab"); - if (!fp) { - throw std::runtime_error("Could not open file for appending: " + - m_filename); - } - m_mode = "a"; - } else { - throw std::runtime_error("Unsupported mode: " + mode); - } -} - -template -void ClusterFile::set_roi(ROI roi) { - m_roi = roi; -} -template -void ClusterFile::set_noise_map( - const NDView noise_map) { - m_noise_map = NDArray(noise_map); -} -template -void ClusterFile::set_gain_map( - const NDView gain_map) { - m_gain_map = GainMap(gain_map); -} - -template -void ClusterFile::set_gain_map(const GainMap &gain_map) { - m_gain_map = gain_map; -} - -template -void ClusterFile::set_gain_map(const GainMap &&gain_map) { - m_gain_map = gain_map; -} - -// TODO generally supported for all clsuter types -template -void ClusterFile::write_frame( - const ClusterVector &clusters) { - if (m_mode != "w" && m_mode != "a") { - throw std::runtime_error("File not opened for writing"); - } - - int32_t frame_number = clusters.frame_number(); - fwrite(&frame_number, sizeof(frame_number), 1, fp); - uint32_t n_clusters = clusters.size(); - fwrite(&n_clusters, sizeof(n_clusters), 1, fp); - fwrite(clusters.data(), clusters.item_size(), clusters.size(), fp); -} - -template -ClusterVector -ClusterFile::read_clusters(size_t n_clusters) { - if (m_mode != "r") { - throw std::runtime_error("File not opened for reading"); - } - if (m_noise_map || m_roi) { - return read_clusters_with_cut(n_clusters); - } else { - return read_clusters_without_cut(n_clusters); - } -} - template ClusterVector ClusterFile::read_clusters_without_cut(size_t n_clusters) { @@ -276,8 +245,8 @@ ClusterFile::read_clusters_without_cut(size_t n_clusters) { // if there are photons left from previous frame read them first if (nph) { if (nph > n_clusters) { - // if we have more photons left in the frame then photons to read we - // read directly the requested number + // if we have more photons left in the frame then photons to + // read we read directly the requested number nn = n_clusters; } else { nn = nph; @@ -343,8 +312,8 @@ ClusterFile::read_clusters_with_cut(size_t n_clusters) { while (fread(&frame_number, sizeof(frame_number), 1, fp)) { if (fread(&m_num_left, sizeof(m_num_left), 1, fp)) { clusters.set_frame_number( - frame_number); // cluster vector will hold the last frame - // number + frame_number); // cluster vector will hold the last + // frame number while (m_num_left && clusters.size() < n_clusters) { ClusterType c = read_one_cluster(); if (is_selected(c)) { @@ -375,18 +344,6 @@ ClusterType ClusterFile::read_one_cluster() { return c; } -template -ClusterVector ClusterFile::read_frame() { - if (m_mode != "r") { - throw std::runtime_error(LOCATION + "File not opened for reading"); - } - if (m_noise_map || m_roi) { - return read_frame_with_cut(); - } else { - return read_frame_without_cut(); - } -} - template ClusterVector ClusterFile::read_frame_without_cut() { From 14211047ffdf4614aa75730a8f2e56eeb762920a Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Wed, 16 Apr 2025 14:22:44 +0200 Subject: [PATCH 45/51] added function warpper around ClusterFinderMT and ClusterCollector to construct object --- python/aare/ClusterFinder.py | 38 +++++++++++++++++++++++++++++++++++- python/aare/__init__.py | 3 ++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/python/aare/ClusterFinder.py b/python/aare/ClusterFinder.py index a2042a4..f678dd1 100644 --- a/python/aare/ClusterFinder.py +++ b/python/aare/ClusterFinder.py @@ -1,5 +1,5 @@ -from ._aare import ClusterFinder_Cluster3x3i +from ._aare import ClusterFinder_Cluster3x3i, ClusterFinder_Cluster2x2i, ClusterFinderMT_Cluster3x3i, ClusterFinderMT_Cluster2x2i, ClusterCollector_Cluster3x3i, ClusterCollector_Cluster2x2i import numpy as np def ClusterFinder(image_size, cluster_size, n_sigma=5, dtype = np.int32, capacity = 1024): @@ -9,6 +9,42 @@ def ClusterFinder(image_size, cluster_size, n_sigma=5, dtype = np.int32, capacit """ if dtype == np.int32 and cluster_size == (3,3): return ClusterFinder_Cluster3x3i(image_size, n_sigma = n_sigma, capacity=capacity) + elif dtype == np.int32 and cluster_size == (2,2): + return ClusterFinder_Cluster2x2i(image_size, n_sigma = n_sigma, capacity=capacity) else: #TODO! add the other formats raise ValueError(f"Unsupported dtype: {dtype}. Only np.int32 is supported.") + + +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++. + """ + + if dtype == np.int32 and cluster_size == (3,3): + return ClusterFinderMT_Cluster3x3i(image_size, n_sigma = n_sigma, + capacity = capacity, n_threads = n_threads) + elif dtype == np.int32 and cluster_size == (2,2): + return ClusterFinderMT_Cluster2x2i(image_size, n_sigma = n_sigma, + capacity = capacity, n_threads = n_threads) + else: + #TODO! add the other formats + raise ValueError(f"Unsupported dtype: {dtype}. Only np.int32 is supported.") + + +def ClusterCollector(clusterfindermt, cluster_size = (3,3), dtype=np.int32): + """ + Factory function to create a ClusterCollector object. Provides a cleaner syntax for + the templated ClusterCollector in C++. + """ + + if dtype == np.int32 and cluster_size == (3,3): + return ClusterCollector_Cluster3x3i(clusterfindermt) + elif dtype == np.int32 and cluster_size == (2,2): + return ClusterCollector_Cluster2x2i(clusterfindermt) + + else: + #TODO! add the other formats + raise ValueError(f"Unsupported dtype: {dtype}. Only np.int32 is supported.") + diff --git a/python/aare/__init__.py b/python/aare/__init__.py index b1eb604..096dddf 100644 --- a/python/aare/__init__.py +++ b/python/aare/__init__.py @@ -11,9 +11,10 @@ from ._aare import ROI # from ._aare import ClusterFinderMT, ClusterCollector, ClusterFileSink, ClusterVector_i -from .ClusterFinder import ClusterFinder +from .ClusterFinder import ClusterFinder, ClusterCollector, ClusterFinderMT from .ClusterVector import ClusterVector + from ._aare import fit_gaus, fit_pol1 from ._aare import Interpolator from ._aare import calculate_eta2 From c49a2fdf8e0fc8a056e8ee1acaa1808101f48866 Mon Sep 17 00:00:00 2001 From: Mazzoleni Alice Francesca Date: Wed, 16 Apr 2025 16:40:42 +0200 Subject: [PATCH 46/51] removed cluster_2x2 and cluster3x3 specializations --- include/aare/Cluster.hpp | 111 +++++++++++------------------- include/aare/ClusterFinder.hpp | 15 ++-- include/aare/GainMap.hpp | 5 +- python/src/bind_ClusterVector.hpp | 65 +++++++++-------- python/src/cluster.hpp | 15 ++-- src/Cluster.test.cpp | 13 ---- src/ClusterFile.test.cpp | 20 +++--- 7 files changed, 93 insertions(+), 151 deletions(-) diff --git a/include/aare/Cluster.hpp b/include/aare/Cluster.hpp index 7eb1a13..889593b 100644 --- a/include/aare/Cluster.hpp +++ b/include/aare/Cluster.hpp @@ -16,94 +16,61 @@ namespace aare { -template -constexpr bool is_valid_cluster = - std::is_arithmetic_v && std::is_integral_v && - (ClusterSizeX > 0) && (ClusterSizeY > 0); - // requires clause c++20 maybe update template >> + typename CoordType = int16_t> struct Cluster { + + static_assert(std::is_arithmetic_v, "T needs to be an arithmetic type"); + static_assert(std::is_integral_v, + "CoordType needs to be an integral type"); + static_assert(ClusterSizeX > 0 && ClusterSizeY > 0, + "Cluster sizes must be bigger than zero"); + CoordType x; CoordType y; - T data[ClusterSizeX * ClusterSizeY]; + std::array data; static constexpr uint8_t cluster_size_x = ClusterSizeX; static constexpr uint8_t cluster_size_y = ClusterSizeY; using value_type = T; using coord_type = CoordType; - T sum() const { - return std::accumulate(data, data + ClusterSizeX * ClusterSizeY, 0); - } + T sum() const { return std::accumulate(data.begin(), data.end(), T{}); } std::pair max_sum_2x2() const { - constexpr size_t num_2x2_subclusters = - (ClusterSizeX - 1) * (ClusterSizeY - 1); + if constexpr (cluster_size_x == 3 && cluster_size_y == 3) { + std::array sum_2x2_subclusters; + sum_2x2_subclusters[0] = data[0] + data[1] + data[3] + data[4]; + sum_2x2_subclusters[1] = data[1] + data[2] + data[4] + data[5]; + sum_2x2_subclusters[2] = data[3] + data[4] + data[6] + data[7]; + sum_2x2_subclusters[3] = data[4] + data[5] + data[7] + data[8]; + int index = std::max_element(sum_2x2_subclusters.begin(), + sum_2x2_subclusters.end()) - + sum_2x2_subclusters.begin(); + return std::make_pair(sum_2x2_subclusters[index], index); + } else if constexpr (cluster_size_x == 2 && cluster_size_y == 2) { + return std::make_pair(data[0] + data[1] + data[2] + data[3], 0); + } else { + constexpr size_t num_2x2_subclusters = + (ClusterSizeX - 1) * (ClusterSizeY - 1); - std::array sum_2x2_subcluster; - for (size_t i = 0; i < ClusterSizeY - 1; ++i) { - for (size_t j = 0; j < ClusterSizeX - 1; ++j) - sum_2x2_subcluster[i * (ClusterSizeX - 1) + j] = - data[i * ClusterSizeX + j] + - data[i * ClusterSizeX + j + 1] + - data[(i + 1) * ClusterSizeX + j] + - data[(i + 1) * ClusterSizeX + j + 1]; + std::array sum_2x2_subcluster; + for (size_t i = 0; i < ClusterSizeY - 1; ++i) { + for (size_t j = 0; j < ClusterSizeX - 1; ++j) + sum_2x2_subcluster[i * (ClusterSizeX - 1) + j] = + data[i * ClusterSizeX + j] + + data[i * ClusterSizeX + j + 1] + + data[(i + 1) * ClusterSizeX + j] + + data[(i + 1) * ClusterSizeX + j + 1]; + } + + int index = std::max_element(sum_2x2_subcluster.begin(), + sum_2x2_subcluster.end()) - + sum_2x2_subcluster.begin(); + return std::make_pair(sum_2x2_subcluster[index], index); } - - int index = std::max_element(sum_2x2_subcluster.begin(), - sum_2x2_subcluster.end()) - - sum_2x2_subcluster.begin(); - return std::make_pair(sum_2x2_subcluster[index], index); - } -}; - -// Specialization for 2x2 clusters (only one sum exists) -template struct Cluster { - int16_t x; - int16_t y; - T data[4]; - - static constexpr uint8_t cluster_size_x = 2; - static constexpr uint8_t cluster_size_y = 2; - using value_type = T; - using coord_type = int16_t; - - T sum() const { return std::accumulate(data, data + 4, 0); } - - std::pair max_sum_2x2() const { - return std::make_pair(data[0] + data[1] + data[2] + data[3], - 0); // Only one possible 2x2 sum - } -}; - -// Specialization for 3x3 clusters -template struct Cluster { - int16_t x; - int16_t y; - T data[9]; - static constexpr uint8_t cluster_size_x = 3; - static constexpr uint8_t cluster_size_y = 3; - using value_type = T; - using coord_type = int16_t; - - T sum() const { return std::accumulate(data, data + 9, 0); } - - std::pair max_sum_2x2() const { - std::array sum_2x2_subclusters; - sum_2x2_subclusters[0] = data[0] + data[1] + data[3] + data[4]; - sum_2x2_subclusters[1] = data[1] + data[2] + data[4] + data[5]; - sum_2x2_subclusters[2] = data[3] + data[4] + data[6] + data[7]; - sum_2x2_subclusters[3] = data[4] + data[5] + data[7] + data[8]; - int index = std::max_element(sum_2x2_subclusters.begin(), - sum_2x2_subclusters.end()) - - sum_2x2_subclusters.begin(); - return std::make_pair(sum_2x2_subclusters[index], index); } }; diff --git a/include/aare/ClusterFinder.hpp b/include/aare/ClusterFinder.hpp index b3538eb..ea11162 100644 --- a/include/aare/ClusterFinder.hpp +++ b/include/aare/ClusterFinder.hpp @@ -77,7 +77,6 @@ class ClusterFinder { int has_center_pixel_y = ClusterSizeY % 2; m_clusters.set_frame_number(frame_number); - std::vector cluster_data(ClusterSizeX * ClusterSizeY); for (int iy = 0; iy < frame.shape(0); iy++) { for (int ix = 0; ix < frame.shape(1); ix++) { @@ -124,8 +123,9 @@ class ClusterFinder { // Store cluster if (value == max) { - // Zero out the cluster data - std::fill(cluster_data.begin(), cluster_data.end(), 0); + ClusterType cluster{}; + cluster.x = ix; + cluster.y = iy; // Fill the cluster data since we have a photon to store // It's worth redoing the look since most of the time we @@ -139,20 +139,15 @@ class ClusterFinder { static_cast(frame(iy + ir, ix + ic)) - static_cast( m_pedestal.mean(iy + ir, ix + ic)); - cluster_data[i] = + cluster.data[i] = tmp; // Watch for out of bounds access i++; } } } - ClusterType new_cluster{}; - new_cluster.x = ix; - new_cluster.y = iy; - std::copy(cluster_data.begin(), cluster_data.end(), - new_cluster.data); // Add the cluster to the output ClusterVector - m_clusters.push_back(new_cluster); + m_clusters.push_back(cluster); } } } diff --git a/include/aare/GainMap.hpp b/include/aare/GainMap.hpp index 41acb33..5311916 100644 --- a/include/aare/GainMap.hpp +++ b/include/aare/GainMap.hpp @@ -44,9 +44,8 @@ class GainMap { cl.data[j] = cl.data[j] * static_cast(m_gain_map(y, x)); } } else { - memset(cl.data, 0, - ClusterSizeX * ClusterSizeY * - sizeof(T)); // clear edge clusters + // clear edge clusters + cl.data.fill(0); } } } diff --git a/python/src/bind_ClusterVector.hpp b/python/src/bind_ClusterVector.hpp index f7fa796..ea02487 100644 --- a/python/src/bind_ClusterVector.hpp +++ b/python/src/bind_ClusterVector.hpp @@ -21,16 +21,14 @@ using namespace aare; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" - template void define_ClusterVector(py::module &m, const std::string &typestr) { - using ClusterType = - Cluster; + using ClusterType = Cluster; auto class_name = fmt::format("ClusterVector_{}", typestr); py::class_, void>>( + Cluster, void>>( m, class_name.c_str(), py::buffer_protocol()) @@ -41,10 +39,11 @@ void define_ClusterVector(py::module &m, const std::string &typestr) { self.push_back(cluster); }) - .def("sum", [](ClusterVector &self) { - auto *vec = new std::vector(self.sum()); - return return_vector(vec); - }) + .def("sum", + [](ClusterVector &self) { + auto *vec = new std::vector(self.sum()); + return return_vector(vec); + }) .def_property_readonly("size", &ClusterVector::size) .def("item_size", &ClusterVector::item_size) .def_property_readonly("fmt", @@ -72,32 +71,30 @@ void define_ClusterVector(py::module &m, const std::string &typestr) { ); }); - // Free functions using ClusterVector - m.def("hitmap", - [](std::array image_size, ClusterVector &cv) { - - // Create a numpy array to hold the hitmap - // The shape of the array is (image_size[0], image_size[1]) - // note that the python array is passed as [row, col] which - // is the opposite of the clusters [x,y] - py::array_t hitmap(image_size); - auto r = hitmap.mutable_unchecked<2>(); - - // Initialize hitmap to 0 - for (py::ssize_t i = 0; i < r.shape(0); i++) - for (py::ssize_t j = 0; j < r.shape(1); j++) - r(i, j) = 0; - + // Free functions using ClusterVector + m.def("hitmap", + [](std::array image_size, ClusterVector &cv) { + // Create a numpy array to hold the hitmap + // The shape of the array is (image_size[0], image_size[1]) + // note that the python array is passed as [row, col] which + // is the opposite of the clusters [x,y] + py::array_t hitmap(image_size); + auto r = hitmap.mutable_unchecked<2>(); - // Loop over the clusters and increment the hitmap - // Skip out of bound clusters - for (const auto& cluster : cv) { - auto x = cluster.x; - auto y = cluster.y; - if(x>( + py::class_>( m, class_name.c_str(), py::buffer_protocol()) .def(py::init([](uint8_t x, uint8_t y, py::array_t data) { py::buffer_info buf_info = data.request(); - Type *ptr = static_cast(buf_info.ptr); - Cluster cluster; + Cluster cluster; cluster.x = x; cluster.y = y; - std::copy(ptr, ptr + ClusterSizeX * ClusterSizeY, - cluster.data); // Copy array contents + auto r = data.template unchecked<1>(); // no bounds checks + for (py::ssize_t i = 0; i < data.size(); ++i) { + cluster.data[i] = r(i); + } return cluster; })); @@ -64,9 +65,6 @@ void define_cluster(py::module &m, const std::string &typestr) { */ } - - - template void define_cluster_finder_mt_bindings(py::module &m, @@ -206,6 +204,5 @@ void define_cluster_finder_bindings(py::module &m, const std::string &typestr) { return; }, py::arg(), py::arg("frame_number") = 0); - } #pragma GCC diagnostic pop diff --git a/src/Cluster.test.cpp b/src/Cluster.test.cpp index 879a5e7..ba9cda1 100644 --- a/src/Cluster.test.cpp +++ b/src/Cluster.test.cpp @@ -14,19 +14,6 @@ using namespace aare; -TEST_CASE("Correct Instantiation of Cluster and ClusterVector", - "[.cluster][.instantiation]") { - - CHECK(is_valid_cluster); - CHECK(is_valid_cluster); - CHECK(not is_valid_cluster); - CHECK(not is_valid_cluster); - CHECK(not is_valid_cluster); - - CHECK(not is_cluster_v); - CHECK(is_cluster_v>); -} - TEST_CASE("Test sum of Cluster", "[.cluster]") { Cluster cluster{0, 0, {1, 2, 3, 4}}; diff --git a/src/ClusterFile.test.cpp b/src/ClusterFile.test.cpp index 024bed4..3f15332 100644 --- a/src/ClusterFile.test.cpp +++ b/src/ClusterFile.test.cpp @@ -311,19 +311,19 @@ TEST_CASE("Write cluster with potential padding", "[.files][.ClusterFile]") { CHECK(read_cluster_vector.at(0).x == clustervec.at(0).x); CHECK(read_cluster_vector.at(0).y == clustervec.at(0).y); - CHECK(std::equal(clustervec.at(0).data, clustervec.at(0).data + 9, - read_cluster_vector.at(0).data, [](double a, double b) { - return std::abs(a - b) < - std::numeric_limits::epsilon(); - })); + CHECK(std::equal( + clustervec.at(0).data.begin(), clustervec.at(0).data.end(), + read_cluster_vector.at(0).data.begin(), [](double a, double b) { + return std::abs(a - b) < std::numeric_limits::epsilon(); + })); CHECK(read_cluster_vector.at(1).x == clustervec.at(1).x); CHECK(read_cluster_vector.at(1).y == clustervec.at(1).y); - CHECK(std::equal(clustervec.at(1).data, std::end(clustervec.at(1).data), - read_cluster_vector.at(1).data, [](double a, double b) { - return std::abs(a - b) < - std::numeric_limits::epsilon(); - })); + CHECK(std::equal( + clustervec.at(1).data.begin(), clustervec.at(1).data.end(), + read_cluster_vector.at(1).data.begin(), [](double a, double b) { + return std::abs(a - b) < std::numeric_limits::epsilon(); + })); } TEST_CASE("Read frame and modify cluster data", "[.files][.ClusterFile]") { From 177459c98a283b5f6afcee8683194f086e3e3a72 Mon Sep 17 00:00:00 2001 From: mazzol_a Date: Thu, 17 Apr 2025 17:09:53 +0200 Subject: [PATCH 47/51] added multithreaded cluster finder test --- CMakeLists.txt | 3 +- include/aare/ClusterCollector.hpp | 6 +- include/aare/ClusterFinderMT.hpp | 3 + src/ClusterFinderMT.test.cpp | 99 +++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 src/ClusterFinderMT.test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b57f05f..3c0d03a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -275,7 +275,7 @@ else() if(CMAKE_BUILD_TYPE STREQUAL "Release") message(STATUS "Release build") - target_compile_options(aare_compiler_flags INTERFACE -O3) + target_compile_options(aare_compiler_flags INTERFACE -O3 -g) else() message(STATUS "Debug build") endif() @@ -426,6 +426,7 @@ if(AARE_TESTS) ${CMAKE_CURRENT_SOURCE_DIR}/src/Cluster.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/CalculateEta.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/ClusterFile.test.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ClusterFinderMT.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Pedestal.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/JungfrauDataFile.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/NumpyFile.test.cpp diff --git a/include/aare/ClusterCollector.hpp b/include/aare/ClusterCollector.hpp index cb49f58..ae78a8e 100644 --- a/include/aare/ClusterCollector.hpp +++ b/include/aare/ClusterCollector.hpp @@ -37,7 +37,11 @@ class ClusterCollector { public: ClusterCollector(ClusterFinderMT *source) { m_source = source->sink(); - m_thread = std::thread(&ClusterCollector::process, this); + m_thread = + std::thread(&ClusterCollector::process, + this); // only one process does that so why isnt it + // automatically written to m_cluster in collect + // - instead of writing first to m_sink? } void stop() { m_stop_requested = true; diff --git a/include/aare/ClusterFinderMT.hpp b/include/aare/ClusterFinderMT.hpp index 29fc715..2dfb279 100644 --- a/include/aare/ClusterFinderMT.hpp +++ b/include/aare/ClusterFinderMT.hpp @@ -34,6 +34,7 @@ template , typename FRAME_TYPE = uint16_t, typename PEDESTAL_TYPE = double> class ClusterFinderMT { + protected: using CT = typename ClusterType::value_type; size_t m_current_thread{0}; size_t m_n_threads{0}; @@ -50,6 +51,7 @@ class ClusterFinderMT { std::thread m_collect_thread; std::chrono::milliseconds m_default_wait{1}; + private: std::atomic m_stop_requested{false}; std::atomic m_processing_threads_stopped{true}; @@ -120,6 +122,7 @@ class ClusterFinderMT { ClusterFinderMT(Shape<2> image_size, PEDESTAL_TYPE nSigma = 5.0, size_t capacity = 2000, size_t n_threads = 3) : m_n_threads(n_threads) { + for (size_t i = 0; i < n_threads; i++) { m_cluster_finders.push_back( std::make_unique< diff --git a/src/ClusterFinderMT.test.cpp b/src/ClusterFinderMT.test.cpp new file mode 100644 index 0000000..9289592 --- /dev/null +++ b/src/ClusterFinderMT.test.cpp @@ -0,0 +1,99 @@ + +#include "aare/ClusterFinderMT.hpp" +#include "aare/Cluster.hpp" +#include "aare/ClusterCollector.hpp" +#include "aare/File.hpp" + +#include "test_config.hpp" + +#include +#include +#include + +using namespace aare; + +// wrapper function to access private member variables for testing +template +class ClusterFinderMTWrapper + : public ClusterFinderMT { + + public: + ClusterFinderMTWrapper(Shape<2> image_size, PEDESTAL_TYPE nSigma = 5.0, + size_t capacity = 2000, size_t n_threads = 3) + : ClusterFinderMT( + image_size, nSigma, capacity, n_threads) {} + + size_t get_m_input_queues_size() const { + return this->m_input_queues.size(); + } + + size_t get_m_output_queues_size() const { + return this->m_output_queues.size(); + } + + size_t get_m_cluster_finders_size() const { + return this->m_cluster_finders.size(); + } + + bool m_output_queues_are_empty() const { + for (auto &queue : this->m_output_queues) { + if (!queue->isEmpty()) + return false; + } + return true; + } + + bool m_input_queues_are_empty() const { + for (auto &queue : this->m_input_queues) { + if (!queue->isEmpty()) + return false; + } + return true; + } + + bool m_sink_is_empty() const { return this->m_sink.isEmpty(); } + + size_t m_sink_size() const { return this->m_sink.sizeGuess(); } +}; + +TEST_CASE("multithreaded cluster finder", "[.files][.ClusterFinder]") { + auto fpath = "/mnt/sls_det_storage/matterhorn_data/aare_test_data/" + "Moench03new/cu_half_speed_master_4.json"; + + File file(fpath); + + size_t n_threads = 2; + size_t n_frames_pd = 10; + + using ClusterType = Cluster; + + ClusterFinderMTWrapper cf( + {static_cast(file.rows()), static_cast(file.cols())}, + 5, 2000, n_threads); // no idea what frame type is!!! default uint16_t + + CHECK(cf.get_m_input_queues_size() == n_threads); + CHECK(cf.get_m_output_queues_size() == n_threads); + CHECK(cf.get_m_cluster_finders_size() == n_threads); + CHECK(cf.m_output_queues_are_empty() == true); + 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()); + } + + cf.stop(); + + CHECK(cf.m_output_queues_are_empty() == true); + CHECK(cf.m_input_queues_are_empty() == true); + + CHECK(cf.m_sink_size() == n_frames_pd); + ClusterCollector clustercollector(&cf); + + clustercollector.stop(); + + CHECK(cf.m_sink_size() == 0); + + auto clustervec = clustercollector.steal_clusters(); + // CHECK(clustervec.size() == ) //dont know how many clusters to expect +} From d5f8daf194e8297c2f02045348963cb2dfd80832 Mon Sep 17 00:00:00 2001 From: mazzol_a Date: Tue, 22 Apr 2025 16:16:31 +0200 Subject: [PATCH 48/51] removed debug option in CMakelist --- CMakeLists.txt | 2 +- python/src/bind_ClusterVector.hpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c0d03a..6820516 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -275,7 +275,7 @@ else() if(CMAKE_BUILD_TYPE STREQUAL "Release") message(STATUS "Release build") - target_compile_options(aare_compiler_flags INTERFACE -O3 -g) + target_compile_options(aare_compiler_flags INTERFACE -O3) else() message(STATUS "Debug build") endif() diff --git a/python/src/bind_ClusterVector.hpp b/python/src/bind_ClusterVector.hpp index ea02487..ecd7a77 100644 --- a/python/src/bind_ClusterVector.hpp +++ b/python/src/bind_ClusterVector.hpp @@ -44,6 +44,11 @@ void define_ClusterVector(py::module &m, const std::string &typestr) { auto *vec = new std::vector(self.sum()); return return_vector(vec); }) + .def("sum_2x2", + [](ClusterVector &self) { + auto *vec = new std::vector(self.sum_2x2()); + return return_vector(vec); + }) .def_property_readonly("size", &ClusterVector::size) .def("item_size", &ClusterVector::item_size) .def_property_readonly("fmt", From 7b5e32a824af294ca6b35d763dd296a23f6b2c8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Fr=C3=B6jdh?= Date: Fri, 25 Apr 2025 10:31:16 +0200 Subject: [PATCH 49/51] Api extra (#166) Changes to be able to run the example notebooks: - Invert gain map on setting (multiplication is faster but user supplies ADU/energy) - Cast after applying gain map not to loose precision (Important for int32 clusters) - "factor" for ClusterFileSink - Cluster size available to be able to create the right file sink --- include/aare/GainMap.hpp | 12 ++++++++++-- python/aare/ClusterFinder.py | 17 +++++++++++++++++ python/aare/__init__.py | 2 +- python/src/bind_ClusterVector.hpp | 9 ++++----- python/src/cluster.hpp | 3 +++ python/src/module.cpp | 11 +++++------ src/ClusterFile.test.cpp | 3 ++- 7 files changed, 42 insertions(+), 15 deletions(-) diff --git a/include/aare/GainMap.hpp b/include/aare/GainMap.hpp index 5311916..621cc9f 100644 --- a/include/aare/GainMap.hpp +++ b/include/aare/GainMap.hpp @@ -16,10 +16,18 @@ class GainMap { public: explicit GainMap(const NDArray &gain_map) - : m_gain_map(gain_map) {}; + : m_gain_map(gain_map) { + for (auto &item : m_gain_map) { + item = 1.0 / item; + } + + }; explicit GainMap(const NDView gain_map) { m_gain_map = NDArray(gain_map); + for (auto &item : m_gain_map) { + item = 1.0 / item; + } } template (m_gain_map(y, x)); + cl.data[j] = static_cast(cl.data[j] * m_gain_map(y, x)); //cast after conversion to keep precision } } else { // clear edge clusters diff --git a/python/aare/ClusterFinder.py b/python/aare/ClusterFinder.py index f678dd1..6e7c352 100644 --- a/python/aare/ClusterFinder.py +++ b/python/aare/ClusterFinder.py @@ -1,5 +1,8 @@ from ._aare import ClusterFinder_Cluster3x3i, ClusterFinder_Cluster2x2i, ClusterFinderMT_Cluster3x3i, ClusterFinderMT_Cluster2x2i, ClusterCollector_Cluster3x3i, ClusterCollector_Cluster2x2i + + +from ._aare import ClusterFileSink_Cluster3x3i, ClusterFileSink_Cluster2x2i import numpy as np def ClusterFinder(image_size, cluster_size, n_sigma=5, dtype = np.int32, capacity = 1024): @@ -48,3 +51,17 @@ def ClusterCollector(clusterfindermt, cluster_size = (3,3), dtype=np.int32): #TODO! add the other formats raise ValueError(f"Unsupported dtype: {dtype}. Only np.int32 is supported.") +def ClusterFileSink(clusterfindermt, cluster_file, dtype=np.int32): + """ + Factory function to create a ClusterCollector object. Provides a cleaner syntax for + the templated ClusterCollector in C++. + """ + + if dtype == np.int32 and clusterfindermt.cluster_size == (3,3): + return ClusterFileSink_Cluster3x3i(clusterfindermt, cluster_file) + elif dtype == np.int32 and clusterfindermt.cluster_size == (2,2): + return ClusterFileSink_Cluster2x2i(clusterfindermt, cluster_file) + + else: + #TODO! add the other formats + raise ValueError(f"Unsupported dtype: {dtype}. Only np.int32 is supported.") \ No newline at end of file diff --git a/python/aare/__init__.py b/python/aare/__init__.py index 81a9b86..e1e5757 100644 --- a/python/aare/__init__.py +++ b/python/aare/__init__.py @@ -11,7 +11,7 @@ from ._aare import ROI # from ._aare import ClusterFinderMT, ClusterCollector, ClusterFileSink, ClusterVector_i -from .ClusterFinder import ClusterFinder, ClusterCollector, ClusterFinderMT +from .ClusterFinder import ClusterFinder, ClusterCollector, ClusterFinderMT, ClusterFileSink from .ClusterVector import ClusterVector diff --git a/python/src/bind_ClusterVector.hpp b/python/src/bind_ClusterVector.hpp index ecd7a77..db8c8a3 100644 --- a/python/src/bind_ClusterVector.hpp +++ b/python/src/bind_ClusterVector.hpp @@ -44,11 +44,10 @@ void define_ClusterVector(py::module &m, const std::string &typestr) { auto *vec = new std::vector(self.sum()); return return_vector(vec); }) - .def("sum_2x2", - [](ClusterVector &self) { - auto *vec = new std::vector(self.sum_2x2()); - return return_vector(vec); - }) + .def("sum_2x2", [](ClusterVector &self){ + auto *vec = new std::vector(self.sum_2x2()); + return return_vector(vec); + }) .def_property_readonly("size", &ClusterVector::size) .def("item_size", &ClusterVector::item_size) .def_property_readonly("fmt", diff --git a/python/src/cluster.hpp b/python/src/cluster.hpp index 6dd05ad..58f137c 100644 --- a/python/src/cluster.hpp +++ b/python/src/cluster.hpp @@ -93,6 +93,9 @@ void define_cluster_finder_mt_bindings(py::module &m, return; }, py::arg(), py::arg("frame_number") = 0) + .def_property_readonly("cluster_size", [](ClusterFinderMT &self){ + return py::make_tuple(ClusterSizeX, ClusterSizeY); + }) .def("clear_pedestal", &ClusterFinderMT::clear_pedestal) .def("sync", &ClusterFinderMT::sync) diff --git a/python/src/module.cpp b/python/src/module.cpp index cac97dd..946a41b 100644 --- a/python/src/module.cpp +++ b/python/src/module.cpp @@ -10,13 +10,12 @@ #include "file.hpp" #include "fit.hpp" #include "interpolation.hpp" -#include "pedestal.hpp" -#include "pixel_map.hpp" -#include "raw_file.hpp" -#include "raw_master_file.hpp" -#include "var_cluster.hpp" #include "raw_sub_file.hpp" - +#include "raw_master_file.hpp" +#include "raw_file.hpp" +#include "pixel_map.hpp" +#include "var_cluster.hpp" +#include "pedestal.hpp" #include "jungfrau_data_file.hpp" // Pybind stuff diff --git a/src/ClusterFile.test.cpp b/src/ClusterFile.test.cpp index 39c45d4..f688c3d 100644 --- a/src/ClusterFile.test.cpp +++ b/src/ClusterFile.test.cpp @@ -10,8 +10,9 @@ using aare::Cluster; using aare::ClusterFile; using aare::ClusterVector; + TEST_CASE("Read one frame from a cluster file", "[.files]") { - // We know that the frame has 97 clusters + //We know that the frame has 97 clusters auto fpath = test_data_path() / "clust" / "single_frame_97_clustrers.clust"; REQUIRE(std::filesystem::exists(fpath)); From f06e722dce1a881eac25302814c8fa96d83e77c9 Mon Sep 17 00:00:00 2001 From: mazzol_a Date: Fri, 25 Apr 2025 11:38:51 +0200 Subject: [PATCH 50/51] changes from PR review --- include/aare/CalculateEta.hpp | 6 +-- include/aare/ClusterVector.hpp | 19 ++++----- include/aare/GainMap.hpp | 3 +- include/aare/Interpolator.hpp | 6 +-- src/ClusterFile.test.cpp | 70 ++++++++++++++++------------------ src/ClusterVector.test.cpp | 2 +- 6 files changed, 50 insertions(+), 56 deletions(-) diff --git a/include/aare/CalculateEta.hpp b/include/aare/CalculateEta.hpp index 289e8bc..37bdf00 100644 --- a/include/aare/CalculateEta.hpp +++ b/include/aare/CalculateEta.hpp @@ -40,8 +40,8 @@ template calculate_eta2(const ClusterVector &clusters) { NDArray eta2({static_cast(clusters.size()), 2}); - for (size_t i = 0; i < clusters.size(); i++) { - auto e = calculate_eta2(clusters.at(i)); + for (const ClusterType &cluster : clusters) { + auto e = calculate_eta2(cluster); eta2(i, 0) = e.x; eta2(i, 1) = e.y; } @@ -122,7 +122,7 @@ calculate_eta2(const Cluster &cl) { return eta; } -// Dont get why this is correct - photon center should be top right corner +// TODO! Look up eta2 calculation - photon center should be top right corner template Eta2 calculate_eta2(const Cluster &cl) { Eta2 eta{}; diff --git a/include/aare/ClusterVector.hpp b/include/aare/ClusterVector.hpp index e91cb6d..5630278 100644 --- a/include/aare/ClusterVector.hpp +++ b/include/aare/ClusterVector.hpp @@ -76,9 +76,9 @@ class ClusterVector> { std::vector sum() { std::vector sums(m_data.size()); - for (size_t i = 0; i < m_data.size(); i++) { - sums[i] = at(i).sum(); - } + std::transform(m_data.begin(), m_data.end(), sums.begin(), + [](const T &cluster) { return cluster.sum(); }); + return sums; } @@ -86,13 +86,14 @@ class ClusterVector> { * @brief Sum the pixels in the 2x2 subcluster with the biggest pixel sum in * each cluster * @return std::vector vector of sums for each cluster - */ //TODO if underlying container is a vector use std::for_each + */ std::vector sum_2x2() { std::vector sums_2x2(m_data.size()); - for (size_t i = 0; i < m_data.size(); i++) { - sums_2x2[i] = at(i).max_sum_2x2().first; - } + std::transform( + m_data.begin(), m_data.end(), sums_2x2.begin(), + [](const T &cluster) { return cluster.max_sum_2x2().first; }); + return sums_2x2; } @@ -149,9 +150,9 @@ class ClusterVector> { * @brief Return a reference to the i-th cluster casted to type V * @tparam V type of the cluster */ - ClusterType &at(size_t i) { return m_data[i]; } + ClusterType &operator[](size_t i) { return m_data[i]; } - const ClusterType &at(size_t i) const { return m_data[i]; } + const ClusterType &operator[](size_t i) const { return m_data[i]; } /** * @brief Return the frame number of the clusters. 0 is used to indicate diff --git a/include/aare/GainMap.hpp b/include/aare/GainMap.hpp index 621cc9f..23ed467 100644 --- a/include/aare/GainMap.hpp +++ b/include/aare/GainMap.hpp @@ -41,8 +41,7 @@ class GainMap { int64_t index_cluster_center_x = ClusterSizeX / 2; int64_t index_cluster_center_y = ClusterSizeY / 2; - for (size_t i = 0; i < clustervec.size(); i++) { - auto &cl = clustervec.at(i); + for (T &cl : clustervec) { if (cl.x > 0 && cl.y > 0 && cl.x < m_gain_map.shape(1) - 1 && cl.y < m_gain_map.shape(0) - 1) { diff --git a/include/aare/Interpolator.hpp b/include/aare/Interpolator.hpp index 85ccf29..d2b2322 100644 --- a/include/aare/Interpolator.hpp +++ b/include/aare/Interpolator.hpp @@ -44,9 +44,8 @@ Interpolator::interpolate(const ClusterVector &clusters) { photons.reserve(clusters.size()); if (clusters.cluster_size_x() == 3 || clusters.cluster_size_y() == 3) { - for (size_t i = 0; i < clusters.size(); i++) { + for (const ClusterType &cluster : clusters) { - auto cluster = clusters.at(i); auto eta = calculate_eta2(cluster); Photon photon; @@ -94,8 +93,7 @@ Interpolator::interpolate(const ClusterVector &clusters) { } } else if (clusters.cluster_size_x() == 2 || clusters.cluster_size_y() == 2) { - for (size_t i = 0; i < clusters.size(); i++) { - auto cluster = clusters.at(i); + for (const ClusterType &cluster : clusters) { auto eta = calculate_eta2(cluster); Photon photon; diff --git a/src/ClusterFile.test.cpp b/src/ClusterFile.test.cpp index f688c3d..6254b5d 100644 --- a/src/ClusterFile.test.cpp +++ b/src/ClusterFile.test.cpp @@ -20,11 +20,10 @@ TEST_CASE("Read one frame from a cluster file", "[.files]") { auto clusters = f.read_frame(); CHECK(clusters.size() == 97); CHECK(clusters.frame_number() == 135); - CHECK(clusters.at(0).x == 1); - CHECK(clusters.at(0).y == 200); + CHECK(clusters[0].x == 1); + CHECK(clusters[0].y == 200); int32_t expected_cluster_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; - CHECK(std::equal(std::begin(clusters.at(0).data), - std::end(clusters.at(0).data), + CHECK(std::equal(std::begin(clusters[0].data), std::end(clusters[0].data), std::begin(expected_cluster_data))); } @@ -47,18 +46,17 @@ TEST_CASE("Read one frame using ROI", "[.files]") { // Check that all clusters are within the ROI for (size_t i = 0; i < clusters.size(); i++) { - auto c = clusters.at(i); + auto c = clusters[i]; REQUIRE(c.x >= roi.xmin); REQUIRE(c.x <= roi.xmax); REQUIRE(c.y >= roi.ymin); REQUIRE(c.y <= roi.ymax); } - CHECK(clusters.at(0).x == 1); - CHECK(clusters.at(0).y == 200); + CHECK(clusters[0].x == 1); + CHECK(clusters[0].y == 200); int32_t expected_cluster_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; - CHECK(std::equal(std::begin(clusters.at(0).data), - std::end(clusters.at(0).data), + CHECK(std::equal(std::begin(clusters[0].data), std::end(clusters[0].data), std::begin(expected_cluster_data))); } @@ -175,10 +173,10 @@ TEST_CASE("Read clusters from single frame file", "[.files]") { REQUIRE(clusters.size() == 50); REQUIRE(clusters.frame_number() == 135); int32_t expected_cluster_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; - REQUIRE(clusters.at(0).x == 1); - REQUIRE(clusters.at(0).y == 200); - CHECK(std::equal(std::begin(clusters.at(0).data), - std::end(clusters.at(0).data), + REQUIRE(clusters[0].x == 1); + REQUIRE(clusters[0].y == 200); + CHECK(std::equal(std::begin(clusters[0].data), + std::end(clusters[0].data), std::begin(expected_cluster_data))); } SECTION("Read more clusters than available") { @@ -188,10 +186,10 @@ TEST_CASE("Read clusters from single frame file", "[.files]") { REQUIRE(clusters.size() == 97); REQUIRE(clusters.frame_number() == 135); int32_t expected_cluster_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; - REQUIRE(clusters.at(0).x == 1); - REQUIRE(clusters.at(0).y == 200); - CHECK(std::equal(std::begin(clusters.at(0).data), - std::end(clusters.at(0).data), + REQUIRE(clusters[0].x == 1); + REQUIRE(clusters[0].y == 200); + CHECK(std::equal(std::begin(clusters[0].data), + std::end(clusters[0].data), std::begin(expected_cluster_data))); } SECTION("Read all clusters") { @@ -199,11 +197,11 @@ TEST_CASE("Read clusters from single frame file", "[.files]") { auto clusters = f.read_clusters(97); REQUIRE(clusters.size() == 97); REQUIRE(clusters.frame_number() == 135); - REQUIRE(clusters.at(0).x == 1); - REQUIRE(clusters.at(0).y == 200); + REQUIRE(clusters[0].x == 1); + REQUIRE(clusters[0].y == 200); int32_t expected_cluster_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; - CHECK(std::equal(std::begin(clusters.at(0).data), - std::end(clusters.at(0).data), + CHECK(std::equal(std::begin(clusters[0].data), + std::end(clusters[0].data), std::begin(expected_cluster_data))); } } @@ -225,11 +223,10 @@ TEST_CASE("Read clusters from single frame file with ROI", "[.files]") { CHECK(clusters.size() == 10); CHECK(clusters.frame_number() == 135); - CHECK(clusters.at(0).x == 1); - CHECK(clusters.at(0).y == 200); + CHECK(clusters[0].x == 1); + CHECK(clusters[0].y == 200); int32_t expected_cluster_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; - CHECK(std::equal(std::begin(clusters.at(0).data), - std::end(clusters.at(0).data), + CHECK(std::equal(std::begin(clusters[0].data), std::end(clusters[0].data), std::begin(expected_cluster_data))); } @@ -314,19 +311,19 @@ TEST_CASE("Write cluster with potential padding", "[.files][.ClusterFile]") { CHECK(read_cluster_vector.size() == 2); CHECK(read_cluster_vector.frame_number() == 0); - CHECK(read_cluster_vector.at(0).x == clustervec.at(0).x); - CHECK(read_cluster_vector.at(0).y == clustervec.at(0).y); + CHECK(read_cluster_vector[0].x == clustervec[0].x); + CHECK(read_cluster_vector[0].y == clustervec[0].y); CHECK(std::equal( - clustervec.at(0).data.begin(), clustervec.at(0).data.end(), - read_cluster_vector.at(0).data.begin(), [](double a, double b) { + clustervec[0].data.begin(), clustervec[0].data.end(), + read_cluster_vector[0].data.begin(), [](double a, double b) { return std::abs(a - b) < std::numeric_limits::epsilon(); })); - CHECK(read_cluster_vector.at(1).x == clustervec.at(1).x); - CHECK(read_cluster_vector.at(1).y == clustervec.at(1).y); + CHECK(read_cluster_vector[1].x == clustervec[1].x); + CHECK(read_cluster_vector[1].y == clustervec[1].y); CHECK(std::equal( - clustervec.at(1).data.begin(), clustervec.at(1).data.end(), - read_cluster_vector.at(1).data.begin(), [](double a, double b) { + clustervec[1].data.begin(), clustervec[1].data.end(), + read_cluster_vector[1].data.begin(), [](double a, double b) { return std::abs(a - b) < std::numeric_limits::epsilon(); })); } @@ -346,10 +343,9 @@ TEST_CASE("Read frame and modify cluster data", "[.files][.ClusterFile]") { Cluster{0, 0, {0, 1, 2, 3, 4, 5, 6, 7, 8}}); CHECK(clusters.size() == 98); - CHECK(clusters.at(0).x == 1); - CHECK(clusters.at(0).y == 200); + CHECK(clusters[0].x == 1); + CHECK(clusters[0].y == 200); - CHECK(std::equal(std::begin(clusters.at(0).data), - std::end(clusters.at(0).data), + CHECK(std::equal(std::begin(clusters[0].data), std::end(clusters[0].data), std::begin(expected_cluster_data))); } diff --git a/src/ClusterVector.test.cpp b/src/ClusterVector.test.cpp index 468a707..1214b6b 100644 --- a/src/ClusterVector.test.cpp +++ b/src/ClusterVector.test.cpp @@ -60,7 +60,7 @@ TEST_CASE("ClusterVector 2x2 int32_t capacity 4, push back then read", REQUIRE(cv.size() == 1); REQUIRE(cv.capacity() == 4); - auto c2 = cv.at(0); + auto c2 = cv[0]; // Check that the data is the same REQUIRE(c1.x == c2.x); From eb6862ff9913726273878e198a76d662b21c1074 Mon Sep 17 00:00:00 2001 From: mazzol_a Date: Fri, 25 Apr 2025 12:03:59 +0200 Subject: [PATCH 51/51] changed name of GainMap to InvertedGainMap --- include/aare/CalculateEta.hpp | 4 ++-- include/aare/ClusterFile.hpp | 19 ++++++++++++------- include/aare/ClusterVector.hpp | 12 +++++++----- include/aare/GainMap.hpp | 24 ++++++++++++++---------- python/src/cluster_file.hpp | 3 --- 5 files changed, 35 insertions(+), 27 deletions(-) diff --git a/include/aare/CalculateEta.hpp b/include/aare/CalculateEta.hpp index 37bdf00..db17dad 100644 --- a/include/aare/CalculateEta.hpp +++ b/include/aare/CalculateEta.hpp @@ -40,8 +40,8 @@ template calculate_eta2(const ClusterVector &clusters) { NDArray eta2({static_cast(clusters.size()), 2}); - for (const ClusterType &cluster : clusters) { - auto e = calculate_eta2(cluster); + for (size_t i = 0; i < clusters.size(); i++) { + auto e = calculate_eta2(clusters[i]); eta2(i, 0) = e.x; eta2(i, 1) = e.y; } diff --git a/include/aare/ClusterFile.hpp b/include/aare/ClusterFile.hpp index f705cfa..ef78874 100644 --- a/include/aare/ClusterFile.hpp +++ b/include/aare/ClusterFile.hpp @@ -46,8 +46,8 @@ class ClusterFile { std::optional m_roi; /*Region of interest, will be applied if set*/ std::optional> m_noise_map; /*Noise map to cut photons, will be applied if set*/ - std::optional m_gain_map; /*Gain map to apply to the clusters, will - be applied if set*/ + std::optional m_gain_map; /*Gain map to apply to the + clusters, will be applied if set*/ public: /** @@ -160,16 +160,21 @@ class ClusterFile { } /** - * @brief Set the gain map to use when reading clusters. If set the gain map will be applied - * to the clusters that pass ROI and noise_map selection. The gain map is expected to be in ADU/energy. + * @brief Set the gain map to use when reading clusters. If set the gain map + * will be applied to the clusters that pass ROI and noise_map selection. + * The gain map is expected to be in ADU/energy. */ void set_gain_map(const NDView gain_map) { - m_gain_map = GainMap(gain_map); + m_gain_map = InvertedGainMap(gain_map); } - void set_gain_map(const GainMap &gain_map) { m_gain_map = gain_map; } + void set_gain_map(const InvertedGainMap &gain_map) { + m_gain_map = gain_map; + } - void set_gain_map(const GainMap &&gain_map) { m_gain_map = gain_map; } + void set_gain_map(const InvertedGainMap &&gain_map) { + m_gain_map = gain_map; + } /** * @brief Close the file. If not closed the file will be diff --git a/include/aare/ClusterVector.hpp b/include/aare/ClusterVector.hpp index 5630278..c8b1ea1 100644 --- a/include/aare/ClusterVector.hpp +++ b/include/aare/ClusterVector.hpp @@ -76,8 +76,9 @@ class ClusterVector> { std::vector sum() { std::vector sums(m_data.size()); - std::transform(m_data.begin(), m_data.end(), sums.begin(), - [](const T &cluster) { return cluster.sum(); }); + std::transform( + m_data.begin(), m_data.end(), sums.begin(), + [](const ClusterType &cluster) { return cluster.sum(); }); return sums; } @@ -90,9 +91,10 @@ class ClusterVector> { std::vector sum_2x2() { std::vector sums_2x2(m_data.size()); - std::transform( - m_data.begin(), m_data.end(), sums_2x2.begin(), - [](const T &cluster) { return cluster.max_sum_2x2().first; }); + std::transform(m_data.begin(), m_data.end(), sums_2x2.begin(), + [](const ClusterType &cluster) { + return cluster.max_sum_2x2().first; + }); return sums_2x2; } diff --git a/include/aare/GainMap.hpp b/include/aare/GainMap.hpp index 23ed467..ac558d0 100644 --- a/include/aare/GainMap.hpp +++ b/include/aare/GainMap.hpp @@ -1,6 +1,7 @@ /************************************************ - * @file ApplyGainMap.hpp - * @short function to apply gain map of image size to a vector of clusters + * @file GainMap.hpp + * @short function to apply gain map of image size to a vector of clusters - + *note stored gainmap is inverted for efficient aaplication to images ***********************************************/ #pragma once @@ -12,18 +13,17 @@ namespace aare { -class GainMap { +class InvertedGainMap { public: - explicit GainMap(const NDArray &gain_map) + explicit InvertedGainMap(const NDArray &gain_map) : m_gain_map(gain_map) { - for (auto &item : m_gain_map) { + for (auto &item : m_gain_map) { item = 1.0 / item; } + }; - }; - - explicit GainMap(const NDView gain_map) { + explicit InvertedGainMap(const NDView gain_map) { m_gain_map = NDArray(gain_map); for (auto &item : m_gain_map) { item = 1.0 / item; @@ -41,14 +41,18 @@ class GainMap { int64_t index_cluster_center_x = ClusterSizeX / 2; int64_t index_cluster_center_y = ClusterSizeY / 2; - for (T &cl : clustervec) { + for (size_t i = 0; i < clustervec.size(); i++) { + auto &cl = clustervec[i]; if (cl.x > 0 && cl.y > 0 && cl.x < m_gain_map.shape(1) - 1 && cl.y < m_gain_map.shape(0) - 1) { for (size_t j = 0; j < ClusterSizeX * ClusterSizeY; j++) { size_t x = cl.x + j % ClusterSizeX - index_cluster_center_x; size_t y = cl.y + j / ClusterSizeX - index_cluster_center_y; - cl.data[j] = static_cast(cl.data[j] * m_gain_map(y, x)); //cast after conversion to keep precision + cl.data[j] = static_cast( + static_cast(cl.data[j]) * + m_gain_map( + y, x)); // cast after conversion to keep precision } } else { // clear edge clusters diff --git a/python/src/cluster_file.hpp b/python/src/cluster_file.hpp index 3e7aa48..ac384b2 100644 --- a/python/src/cluster_file.hpp +++ b/python/src/cluster_file.hpp @@ -59,9 +59,6 @@ void define_cluster_file_io_bindings(py::module &m, self.set_gain_map(view); }) - // void set_gain_map(const GainMap &gain_map); //TODO do i need a - // gainmap constructor? - .def("close", &ClusterFile::close) .def("write_frame", &ClusterFile::write_frame) .def("__enter__", [](ClusterFile &self) { return &self; })