From fc76f36413fa593aa6f4db8be0a58aee0dcaf143 Mon Sep 17 00:00:00 2001 From: Erik Frojdh Date: Tue, 2 Jun 2026 15:24:01 +0200 Subject: [PATCH] added timer and file processing --- .../aare/PedestalTrackingPixelHistogram.hpp | 5 + include/aare/PixelHistogramImpl.hpp | 1 + python/aare/__init__.py | 2 +- python/aare/utils.py | 17 ++- .../bind_PedestalTrackingPixelHistogram.hpp | 19 ++++ src/PedestalTrackingPixelHistogram.cpp | 102 ++++++++++++++++++ 6 files changed, 144 insertions(+), 2 deletions(-) diff --git a/include/aare/PedestalTrackingPixelHistogram.hpp b/include/aare/PedestalTrackingPixelHistogram.hpp index 9fc3044..9f6684c 100644 --- a/include/aare/PedestalTrackingPixelHistogram.hpp +++ b/include/aare/PedestalTrackingPixelHistogram.hpp @@ -14,6 +14,7 @@ #include #include #include +#include namespace aare { @@ -103,6 +104,10 @@ class PedestalTrackingPixelHistogram { void fill_async(NDArray image); + void fill_from_file(const std::filesystem::path &fname, ssize_t max_frames = -1, bool verbose = false); + + void process_pedestal_file(const std::filesystem::path &fname, ssize_t max_frames = -1, bool verbose = false); + // Sigma multiplier for the pedestal-update gate in // fill_async. Atomic; safe to read/write at any // time (the new value takes effect on subsequent pixel evaluations). diff --git a/include/aare/PixelHistogramImpl.hpp b/include/aare/PixelHistogramImpl.hpp index 5c8b474..468bdb1 100644 --- a/include/aare/PixelHistogramImpl.hpp +++ b/include/aare/PixelHistogramImpl.hpp @@ -84,6 +84,7 @@ void PixelHistogramImpl::fill(const NDView &frame) { template void PixelHistogramImpl::fill(int row, int col, T value) { //TODO! add out of bounds check on row and col??? + if (value < m_xmin || value >= m_xmax) { return; } diff --git a/python/aare/__init__.py b/python/aare/__init__.py index 256fff7..b677c13 100644 --- a/python/aare/__init__.py +++ b/python/aare/__init__.py @@ -33,7 +33,7 @@ from .CtbRawFile import CtbRawFile from .RawFile import RawFile from .ScanParameters import ScanParameters -from .utils import random_pixels, random_pixel, flat_list, add_colorbar +from .utils import random_pixels, random_pixel, flat_list, add_colorbar, Timer #make functions available in the top level API diff --git a/python/aare/utils.py b/python/aare/utils.py index 2e5d2d3..98d2349 100644 --- a/python/aare/utils.py +++ b/python/aare/utils.py @@ -2,6 +2,7 @@ import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.axes_grid1 import make_axes_locatable +import time def random_pixels(n_pixels, xmin=0, xmax=512, ymin=0, ymax=1024): """Return a list of random pixels. @@ -34,4 +35,18 @@ def add_colorbar(ax, im, size="5%", pad=0.05): divider = make_axes_locatable(ax) cax = divider.append_axes("right", size=size, pad=pad) plt.colorbar(im, cax=cax) - return ax, im, cax \ No newline at end of file + return ax, im, cax + + +class Timer: + def __init__(self, label="Elapsed time:", verbose=True): + self.label = label + self.verbose = verbose + def __enter__(self): + self.start = time.perf_counter() + return self + + def __exit__(self, exc_type, exc, tb): + self.elapsed = time.perf_counter() - self.start + if self.verbose: + print(f"{self.label} {self.elapsed:.3f}s") \ No newline at end of file diff --git a/python/src/bind_PedestalTrackingPixelHistogram.hpp b/python/src/bind_PedestalTrackingPixelHistogram.hpp index 1ef1f3c..c42b556 100644 --- a/python/src/bind_PedestalTrackingPixelHistogram.hpp +++ b/python/src/bind_PedestalTrackingPixelHistogram.hpp @@ -142,6 +142,25 @@ void define_pedestal_tracking_pixel_histogram_bindings(py::module &m) { )", py::arg("image").noconvert()) + + .def("fill_from_file", &PedestalTrackingPixelHistogram::fill_from_file, + R"( + Fill the histogram from a file. + + Args: + file_path: Path to the file to fill from + max_frames: Maximum number of frames to fill from the file (default: -1) + )",py::call_guard(), + py::arg("fname"), py::arg("max_frames") = -1, py::arg("verbose") = false) + .def("process_pedestal_file", &PedestalTrackingPixelHistogram::process_pedestal_file, + R"( + Process a pedestal file. + + Args: + file_path: Path to the file to process + max_frames: Maximum number of frames to process from the file (default: -1) + )",py::call_guard(), + py::arg("fname"), py::arg("max_frames") = -1, py::arg("verbose") = false) .def_property("n_sigma", &PedestalTrackingPixelHistogram::n_sigma, &PedestalTrackingPixelHistogram::set_n_sigma, R"( diff --git a/src/PedestalTrackingPixelHistogram.cpp b/src/PedestalTrackingPixelHistogram.cpp index de8adad..7868979 100644 --- a/src/PedestalTrackingPixelHistogram.cpp +++ b/src/PedestalTrackingPixelHistogram.cpp @@ -1,12 +1,15 @@ #include "aare/PedestalTrackingPixelHistogram.hpp" +#include "aare/File.hpp" #include +#include #include #include #include #include #include +#include namespace aare { PedestalTrackingPixelHistogram::PedestalTrackingPixelHistogram( @@ -386,4 +389,103 @@ PedestalTrackingPixelHistogram::bin_edges() const { return partial_hists_.front().bin_edges(); } +void PedestalTrackingPixelHistogram::fill_from_file(const std::filesystem::path &fname, ssize_t max_frames, bool verbose) { + constexpr std::size_t progress_interval = 66; + auto last = std::chrono::steady_clock::now(); + + File f(fname); + //check that row col matches constructor + if (f.rows() != rows_ || f.cols() != cols_) { + throw std::invalid_argument( + "PedestalTrackingPixelHistogram: Frame in file {} has shape ({}, {}) does not match " + "constructor shape"); + } + + + const ssize_t total_frames = f.total_frames(); + const ssize_t n_frames = max_frames == -1 ? total_frames : std::min(max_frames, total_frames); + for (ssize_t i = 0; i < n_frames; ++i) { + aare::NDArray frame({rows_, cols_}); + f.read_into(reinterpret_cast(frame.data())); + fill_async(frame); + + // print progress + if (verbose && ((i + 1) % progress_interval == 0 || (i + 1 == n_frames))) { + const auto now = std::chrono::steady_clock::now(); + const double dt = + std::chrono::duration(now - last).count(); + const std::size_t done_in_interval = + (i + 1) % progress_interval == 0 + ? progress_interval + : (i + 1) % progress_interval; + const double fps = + dt > 0.0 ? static_cast(done_in_interval) / dt + : 0.0; + // Carriage return (no newline) so the line is rewritten + // in place; flush since stdout is line-buffered. + + fmt::print("\rProgress: {}/{} ({:.1f}%) {:.1f} FPS ", + i + 1, n_frames, + 100.0 * static_cast(i + 1) / + static_cast(n_frames), + fps); + std::fflush(stdout); + last = now; + } + + } + flush(); + if (verbose) { + fmt::print("\n\n"); + std::fflush(stdout); + } +} + +void PedestalTrackingPixelHistogram::process_pedestal_file(const std::filesystem::path &fname, ssize_t max_frames, bool verbose) { + constexpr std::size_t progress_interval = 66; + auto last = std::chrono::steady_clock::now(); + + File f(fname); + //check that row col matches constructor + if (f.rows() != rows_ || f.cols() != cols_) { + throw std::invalid_argument( + "PedestalTrackingPixelHistogram: Frame in file {} has shape ({}, {}) does not match " + "constructor shape"); + } + + const ssize_t total_frames = f.total_frames(); + const ssize_t n_frames = max_frames == -1 ? total_frames : std::min(max_frames, total_frames); + + aare::NDArray frame({rows_, cols_}); + for (ssize_t i = 0; i < n_frames; ++i) { + f.read_into(reinterpret_cast(frame.data())); + push_pedestal_no_update(frame.view()); + if (verbose && ((i + 1) % progress_interval == 0 || (i + 1 == n_frames))) { + const auto now = std::chrono::steady_clock::now(); + const double dt = + std::chrono::duration(now - last).count(); + const std::size_t done_in_interval = + (i + 1) % progress_interval == 0 + ? progress_interval + : (i + 1) % progress_interval; + const double fps = + dt > 0.0 ? static_cast(done_in_interval) / dt + : 0.0; + fmt::print("\rProgress: {}/{} ({:.1f}%) {:.1f} FPS ", + i + 1, n_frames, + 100.0 * static_cast(i + 1) / + static_cast(n_frames), + fps); + std::fflush(stdout); + last = now; + } + } + update_mean(); + flush(); + if (verbose) { + fmt::print("\n\n"); + std::fflush(stdout); + } +} + } // namespace aare