ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
Histogram.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2016-2022 The ESPResSo project
3 *
4 * This file is part of ESPResSo.
5 *
6 * ESPResSo is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * ESPResSo is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19#ifndef UTILS_HISTOGRAM_HPP
20#define UTILS_HISTOGRAM_HPP
21
22#include "utils/Span.hpp"
23
24#include <boost/multi_array.hpp>
25
26#include <algorithm>
27#include <array>
28#include <cassert>
29#include <cmath>
30#include <cstddef>
31#include <functional>
32#include <numeric>
33#include <stdexcept>
34#include <utility>
35#include <vector>
36
37namespace Utils {
38
39/**
40 * \brief Histogram in Cartesian coordinates.
41 * \tparam T Histogram data type.
42 * \tparam N Histogram data dimensionality.
43 * \tparam M Coordinates data dimensionality.
44 * \tparam U Coordinates data type.
45 */
46template <typename T, std::size_t N, std::size_t M = 3, typename U = double>
47class Histogram {
48 using array_type = boost::multi_array<T, M + 1>;
49 using count_type = boost::multi_array<std::size_t, M + 1>;
50 using array_index = typename array_type::index;
51
52public:
53 /**
54 * \brief Histogram constructor.
55 * \param n_bins the number of bins in each histogram dimension.
56 * \param limits the minimum/maximum data values to consider for the
57 * histogram.
58 */
59 Histogram(std::array<std::size_t, M> n_bins,
60 std::array<std::pair<U, U>, M> limits)
61 : m_n_bins(std::move(n_bins)), m_limits(std::move(limits)),
62 m_bin_sizes(calc_bin_sizes()), m_array(m_array_dim()),
63 m_count(m_array_dim()) {
64 m_ones.fill(T{1});
65 }
66
67 virtual ~Histogram() = default;
68
69 /** \brief Get the number of bins for each dimension. */
70 std::array<std::size_t, M> get_n_bins() const { return m_n_bins; }
71
72 /** \brief Get the histogram data. */
73 std::vector<T> get_histogram() const {
74 return {m_array.data(), m_array.data() + m_array.num_elements()};
75 }
76
77 /** \brief Get the histogram count data. */
78 std::vector<std::size_t> get_tot_count() const {
79 return {m_count.data(), m_count.data() + m_count.num_elements()};
80 }
81
82 /** \brief Get the ranges (min, max) for each dimension. */
83 std::array<std::pair<U, U>, M> get_limits() const { return m_limits; }
84
85 /** \brief Get the bin sizes. */
86 std::array<U, M> get_bin_sizes() const { return m_bin_sizes; }
87
88 /**
89 * \brief Add data to the histogram.
90 * \param pos Position to update.
91 */
93
94 /**
95 * \brief Add data to the histogram.
96 * \param pos Position to update.
97 * \param value Value to add.
98 */
100 if (pos.size() != M) {
101 throw std::invalid_argument("Wrong dimensions for the coordinates");
102 }
103 if (value.size() != N) {
104 throw std::invalid_argument("Wrong dimensions for the value");
105 }
106 if (check_limits(pos)) {
107 boost::array<array_index, M + 1> index;
108 for (std::size_t i = 0; i < M; ++i) {
109 index[i] = calc_bin_index(pos[i], m_limits[i].first, m_bin_sizes[i]);
110 }
111 for (array_index i = 0; i < static_cast<array_index>(N); ++i) {
112 index.back() = i;
113 m_array(index) += value[i];
114 m_count(index)++;
115 }
116 }
117 }
118
119 /** \brief Normalize histogram. */
120 virtual void normalize() {
121 auto const bin_volume = std::accumulate(
122 m_bin_sizes.begin(), m_bin_sizes.end(), U{1}, std::multiplies<U>());
123 std::transform(
124 m_array.data(), m_array.data() + m_array.num_elements(), m_array.data(),
125 [bin_volume](T v) { return static_cast<T>(v / bin_volume); });
126 }
127
128private:
129 /**
130 * \brief Calculate the bin index.
131 * \param value Position on that dimension.
132 * \param offset Bin offset on that dimension.
133 * \param size Bin size on that dimension.
134 */
135 array_index calc_bin_index(double value, double offset, double size) const {
136 return static_cast<array_index>(std::floor((value - offset) / size));
137 }
138
139 /**
140 * \brief Calculate the bin sizes.
141 */
142 std::array<U, M> calc_bin_sizes() const {
143 std::array<U, M> bin_sizes;
144 for (std::size_t i = 0; i < M; ++i) {
145 bin_sizes[i] = (m_limits[i].second - m_limits[i].first) /
146 static_cast<U>(m_n_bins[i]);
147 }
148 return bin_sizes;
149 }
150
151 /**
152 * \brief Check if the position lies within the histogram limits.
153 * \param pos Position to check.
154 */
155 bool check_limits(Span<const U> pos) const {
156 assert(pos.size() == M);
157 bool within_range = true;
158 for (std::size_t i = 0; i < M; ++i) {
159 if (pos[i] < m_limits[i].first or pos[i] >= m_limits[i].second)
160 within_range = false;
161 }
162 return within_range;
163 }
164
165 std::array<std::size_t, M + 1> m_array_dim() const {
166 std::array<std::size_t, M + 1> dimensions;
167 std::copy(m_n_bins.begin(), m_n_bins.end(), dimensions.begin());
168 dimensions.back() = N;
169 return dimensions;
170 }
171
172protected:
173 /// Number of bins for each dimension.
174 std::array<std::size_t, M> m_n_bins;
175 /// Min and max values for each dimension.
176 std::array<std::pair<U, U>, M> m_limits;
177 /// Bin sizes for each dimension.
178 std::array<U, M> m_bin_sizes;
179 /// Histogram data.
180 array_type m_array;
181 /// Track the number of total hits per bin entry.
182 count_type m_count;
183 std::array<T, N> m_ones;
184};
185
186/**
187 * \brief Histogram in cylindrical coordinates.
188 * \tparam T Histogram data type.
189 * \tparam N Histogram data dimensionality.
190 * \tparam M Coordinates data dimensionality.
191 * \tparam U Coordinates data type.
192 */
193template <typename T, std::size_t N, std::size_t M = 3, typename U = double>
194class CylindricalHistogram : public Histogram<T, N, M, U> {
195 using Histogram<T, N, M, U>::m_n_bins;
196 using Histogram<T, N, M, U>::m_limits;
197 using Histogram<T, N, M, U>::m_bin_sizes;
198 using Histogram<T, N, M, U>::m_array;
199
200public:
201 using Histogram<T, N, M, U>::Histogram;
202
203 void normalize() override {
204 auto const min_r = m_limits[0].first;
205 auto const r_bin_size = m_bin_sizes[0];
206 auto const phi_bin_size = m_bin_sizes[1];
207 auto const z_bin_size = m_bin_sizes[2];
208 auto const n_bins_r = m_n_bins[0];
209 for (std::size_t i = 0; i < n_bins_r; i++) {
210 auto const r_left = min_r + static_cast<U>(i) * r_bin_size;
211 auto const r_right = r_left + r_bin_size;
212 auto const bin_volume =
213 (r_right * r_right - r_left * r_left) * z_bin_size * phi_bin_size / 2;
214 auto *begin = m_array[i].origin();
215 std::transform(
216 begin, begin + m_array[i].num_elements(), begin,
217 [bin_volume](T v) { return static_cast<T>(v / bin_volume); });
218 }
219 }
220};
221
222} // Namespace Utils
223
224#endif
__shared__ int pos[MAXDEPTH *THREADS5/WARPSIZE]
float N[3]
Histogram in cylindrical coordinates.
Histogram in Cartesian coordinates.
Definition Histogram.hpp:47
std::array< U, M > get_bin_sizes() const
Get the bin sizes.
Definition Histogram.hpp:86
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.
void update(Span< const U > pos, Span< const T > value)
Add data to the histogram.
Definition Histogram.hpp:99
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.
std::array< T, N > m_ones
std::vector< std::size_t > get_tot_count() const
Get the histogram count data.
Definition Histogram.hpp:78
std::vector< T > get_histogram() const
Get the histogram data.
Definition Histogram.hpp:73
array_type m_array
Histogram data.
void update(Span< const U > pos)
Add data to the histogram.
Definition Histogram.hpp:92
std::array< std::pair< U, U >, M > get_limits() const
Get the ranges (min, max) for each dimension.
Definition Histogram.hpp:83
Histogram(std::array< std::size_t, M > n_bins, std::array< std::pair< U, U >, M > limits)
Histogram constructor.
Definition Histogram.hpp:59
std::array< std::size_t, M > get_n_bins() const
Get the number of bins for each dimension.
Definition Histogram.hpp:70
A stripped-down version of std::span from C++17.
Definition Span.hpp:38
DEVICE_QUALIFIER constexpr size_type size() const
Definition Span.hpp:86