22#include <boost/multi_array.hpp>
45template <
typename T, std::
size_t N, std::
size_t M = 3,
typename U =
double>
47 using array_type = boost::multi_array<T, M + 1>;
48 using count_type = boost::multi_array<std::size_t, M + 1>;
61 std::array<std::pair<U, U>, M> limits)
100 void update(std::span<const U> pos, std::span<const T> value) {
101 if (pos.size() != M) {
102 throw std::invalid_argument(
"Wrong dimensions for the coordinates");
104 if (value.size() != N) {
105 throw std::invalid_argument(
"Wrong dimensions for the value");
107 if (check_limits(pos)) {
108 auto index = calc_bin_index(pos);
109 for (std::size_t i = 0; i < N; ++i) {
119 auto const bin_volume = std::accumulate(
121 std::ranges::transform(
123 [bin_volume](T v) { return static_cast<T>(v / bin_volume); });
131 auto calc_bin_index(std::span<const U>
const &pos)
const {
132 boost::array<array_index, M + 1> index;
133 for (std::size_t i = 0; i < M; ++i) {
134 auto const offset =
m_limits[i].first;
136 auto const n_bins =
static_cast<long>(
m_n_bins[i]);
137 auto const bin =
static_cast<long>(std::floor((pos[i] - offset) / size));
141 index[i] =
static_cast<array_index>(std::clamp(bin, 0l, n_bins - 1l));
149 std::array<U, M> calc_bin_sizes()
const {
150 std::array<U, M> bin_sizes;
151 for (std::size_t i = 0; i < M; ++i) {
162 bool check_limits(std::span<const U>
const &pos)
const {
163 assert(pos.size() == M);
165 return std::ranges::all_of(pos, [&it_limits](U
const value) {
166 auto const [lower, upper] = *it_limits;
168 return value >= lower and value < upper;
172 std::array<std::size_t, M + 1> m_array_dim()
const {
173 std::array<std::size_t, M + 1> dimensions;
174 std::ranges::copy(
m_n_bins, dimensions.begin());
175 dimensions.back() = N;
200template <
typename T, std::
size_t N, std::
size_t M = 3,
typename U =
double>
213 auto const min_r = m_limits[0].first;
214 auto const r_bin_size = m_bin_sizes[0];
215 auto const phi_bin_size = m_bin_sizes[1];
216 auto const z_bin_size = m_bin_sizes[2];
217 auto const n_bins_r =
static_cast<array_index
>(m_n_bins[0]);
218 for (array_index i = 0; i < n_bins_r; i++) {
219 auto const r_left = min_r +
static_cast<U
>(i) * r_bin_size;
220 auto const r_right = r_left + r_bin_size;
221 auto const bin_volume = (r_right * r_right - r_left * r_left) *
222 z_bin_size * phi_bin_size / U(2);
223 auto *begin = m_array[i].origin();
224 std::ranges::transform(
225 std::span(begin, m_array[i].num_elements()), begin,
226 [bin_volume](T v) {
return static_cast<T
>(v / bin_volume); });
Histogram in cylindrical coordinates.
void normalize() override
Histogram in Cartesian coordinates.
std::array< U, M > get_bin_sizes() const
Get the bin sizes.
std::array< std::size_t, M > m_n_bins
Number of bins for each dimension.
std::array< U, M > m_bin_sizes
Bin sizes for each dimension.
virtual void normalize()
Normalize histogram.
std::array< std::pair< U, U >, M > m_limits
Min and max values for each dimension.
virtual ~Histogram()=default
count_type m_count
Track the number of total hits per bin entry.
typename array_type::index array_index
std::array< T, N > m_ones
std::vector< std::size_t > get_tot_count() const
Get the histogram count data.
std::vector< T > get_histogram() const
Get the histogram data.
void update(std::span< const U > pos, std::span< const T > value)
Add data to the histogram.
array_type m_array
Histogram data.
std::array< std::pair< U, U >, M > get_limits() const
Get the ranges (min, max) for each dimension.
Histogram(std::array< std::size_t, M > n_bins, std::array< std::pair< U, U >, M > limits)
Histogram constructor.
std::array< std::size_t, M > get_n_bins() const
Get the number of bins for each dimension.
void update(std::span< const U > pos)
Add data to the histogram.