CLUEstering
High-performance density-based weighted clustering library developed at CERN
Loading...
Searching...
No Matches
Tiles.hpp
1
2#pragma once
3
5#include "CLUEstering/data_structures/internal/SearchBox.hpp"
6#include "CLUEstering/data_structures/internal/VecArray.hpp"
7#include "CLUEstering/detail/concepts.hpp"
8#include "CLUEstering/detail/make_array.hpp"
9#include "CLUEstering/internal/alpaka/work_division.hpp"
10#include "CLUEstering/internal/alpaka/config.hpp"
11#include "CLUEstering/internal/alpaka/memory.hpp"
12#include "CLUEstering/internal/math/math.hpp"
13
14#include <cstddef>
15#include <cstdint>
16#include <cstdint>
17#include <alpaka/alpaka.hpp>
18
19namespace clue {
20
21 template <uint8_t Ndim>
22 class CoordinateExtremes {
23 private:
24 float m_data[2 * Ndim];
25
26 public:
27 CoordinateExtremes() = default;
28
29 ALPAKA_FN_HOST_ACC const float* data() const { return m_data; }
30 ALPAKA_FN_HOST_ACC float* data() { return m_data; }
31
32 ALPAKA_FN_HOST_ACC float min(int i) const { return m_data[2 * i]; }
33 ALPAKA_FN_HOST_ACC float& min(int i) { return m_data[2 * i]; }
34 ALPAKA_FN_HOST_ACC float max(int i) const { return m_data[2 * i + 1]; }
35 ALPAKA_FN_HOST_ACC float& max(int i) { return m_data[2 * i + 1]; }
36 ALPAKA_FN_HOST_ACC float range(int i) const { return max(i) - min(i); }
37 };
38
39 template <uint8_t Ndim>
41 int32_t* indexes;
42 int32_t* offsets;
44 float* tilesizes;
45 uint8_t* wrapping;
46 int32_t npoints;
47 int32_t ntiles;
48 int32_t nperdim;
49
50 ALPAKA_FN_ACC inline constexpr const float* minMax() const { return minmax; }
51 ALPAKA_FN_ACC inline constexpr float* minMax() { return minmax; }
52
53 ALPAKA_FN_ACC inline constexpr const float* tileSize() const { return tilesizes; }
54 ALPAKA_FN_ACC inline constexpr float* tileSize() { return tilesizes; }
55
56 ALPAKA_FN_ACC inline constexpr const uint8_t* wrapped() const { return wrapping; }
57 ALPAKA_FN_ACC inline constexpr uint8_t* wrapped() { return wrapping; }
58
59 ALPAKA_FN_ACC inline constexpr int getBin(float coord, int dim) const {
60 int coord_bin;
61 if (wrapping[dim]) {
62 coord_bin =
63 static_cast<int>((normalizeCoordinate(coord, dim) - minmax->min(dim)) / tilesizes[dim]);
64 } else {
65 coord_bin = static_cast<int>((coord - minmax->min(dim)) / tilesizes[dim]);
66 }
67
68 // Address the cases of underflow and overflow
69 coord_bin = internal::math::min(coord_bin, nperdim - 1);
70 coord_bin = internal::math::max(coord_bin, 0);
71
72 return coord_bin;
73 }
74
75 ALPAKA_FN_ACC inline constexpr int getGlobalBin(const float* coords) const {
76 int global_bin = 0;
77 for (int dim = 0; dim != Ndim - 1; ++dim) {
78 global_bin += internal::math::pow(static_cast<float>(nperdim), Ndim - dim - 1) *
79 getBin(coords[dim], dim);
80 }
81 global_bin += getBin(coords[Ndim - 1], Ndim - 1);
82 return global_bin;
83 }
84
85 ALPAKA_FN_ACC inline constexpr int getGlobalBinByBin(const VecArray<int32_t, Ndim>& Bins) const {
86 int32_t globalBin = 0;
87 for (int dim = 0; dim != Ndim; ++dim) {
88 auto bin_i = wrapping[dim] ? (Bins[dim] % nperdim) : Bins[dim];
89 globalBin += internal::math::pow(static_cast<float>(nperdim), Ndim - dim - 1) * bin_i;
90 }
91 return globalBin;
92 }
93
94 ALPAKA_FN_ACC inline void searchBox(const SearchBoxExtremes<Ndim>& searchbox_extremes,
95 SearchBoxBins<Ndim>& searchbox_bins) {
96 for (int dim{}; dim != Ndim; ++dim) {
97 auto infBin = getBin(searchbox_extremes[dim][0], dim);
98 auto supBin = getBin(searchbox_extremes[dim][1], dim);
99 if (wrapping[dim] and infBin > supBin)
100 supBin += nperdim;
101
102 searchbox_bins[dim] = nostd::make_array(infBin, supBin);
103 }
104 }
105
106 ALPAKA_FN_ACC inline constexpr clue::Span<int32_t> operator[](int32_t globalBinId) {
107 const auto size = offsets[globalBinId + 1] - offsets[globalBinId];
108 const auto offset = offsets[globalBinId];
109 int32_t* buf_ptr = indexes + offset;
110 return clue::Span<int32_t>{buf_ptr, size};
111 }
112
113 ALPAKA_FN_HOST_ACC inline constexpr float normalizeCoordinate(float coord, int dim) const {
114 const float range = minmax->range(dim);
115 float remainder = coord - static_cast<int>(coord / range) * range;
116 if (remainder >= minmax->max(dim))
117 remainder -= range;
118 else if (remainder < minmax->min(dim))
119 remainder += range;
120 return remainder;
121 }
122
123 ALPAKA_FN_ACC inline float distance(const std::array<float, Ndim>& coord_i,
124 const std::array<float, Ndim>& coord_j) {
125 float dist_sq = 0.f;
126 for (int dim = 0; dim != Ndim; ++dim) {
127 if (wrapping[dim])
128 dist_sq += normalizeCoordinate(coord_i[dim] - coord_j[dim], dim) *
129 normalizeCoordinate(coord_i[dim] - coord_j[dim], dim);
130 else
131 dist_sq += (coord_i[dim] - coord_j[dim]) * (coord_i[dim] - coord_j[dim]);
132 }
133 return dist_sq;
134 }
135 };
136
137 template <uint8_t Ndim, concepts::device TDev>
138 class TilesAlpaka {
139 public:
140 template <concepts::queue TQueue>
141 TilesAlpaka(TQueue& queue, int32_t n_points, int32_t n_tiles)
142 : m_assoc{AssociationMap<TDev>(n_points, n_tiles, queue)},
143 m_minmax{make_device_buffer<CoordinateExtremes<Ndim>>(queue)},
144 m_tilesizes{make_device_buffer<float[Ndim]>(queue)},
145 m_wrapped{make_device_buffer<uint8_t[Ndim]>(queue)},
146 m_ntiles{n_tiles},
147 m_nperdim{static_cast<int32_t>(std::pow(n_tiles, 1.f / Ndim))},
148 m_view{} {
149 m_view.indexes = m_assoc.indexes().data();
150 m_view.offsets = m_assoc.offsets().data();
151 m_view.minmax = m_minmax.data();
152 m_view.tilesizes = m_tilesizes.data();
153 m_view.wrapping = m_wrapped.data();
154 m_view.npoints = n_points;
155 m_view.ntiles = m_ntiles;
156 m_view.nperdim = m_nperdim;
157 }
158
159 const TilesAlpakaView<Ndim>& view() const { return m_view; }
160 TilesAlpakaView<Ndim>& view() { return m_view; }
161
162 template <concepts::queue TQueue>
163 ALPAKA_FN_HOST void initialize(int32_t npoints, int32_t ntiles, int32_t nperdim, TQueue& queue) {
164 m_assoc.initialize(npoints, ntiles, queue);
165 m_ntiles = ntiles;
166 m_nperdim = nperdim;
167
168 m_view.indexes = m_assoc.indexes().data();
169 m_view.offsets = m_assoc.offsets().data();
170 m_view.minmax = m_minmax.data();
171 m_view.tilesizes = m_tilesizes.data();
172 m_view.wrapping = m_wrapped.data();
173 m_view.npoints = npoints;
174 m_view.ntiles = ntiles;
175 m_view.nperdim = nperdim;
176 }
177
178 template <concepts::queue TQueue>
179 ALPAKA_FN_HOST void reset(int32_t npoints, int32_t ntiles, int32_t nperdim, TQueue& queue) {
180 m_assoc.reset(queue, npoints, ntiles);
181
182 m_ntiles = ntiles;
183 m_nperdim = nperdim;
184 m_view.indexes = m_assoc.indexes().data();
185 m_view.offsets = m_assoc.offsets().data();
186 m_view.minmax = m_minmax.data();
187 m_view.tilesizes = m_tilesizes.data();
188 m_view.wrapping = m_wrapped.data();
189 m_view.npoints = npoints;
190 m_view.ntiles = ntiles;
191 m_view.nperdim = nperdim;
192 }
193
195 PointsView pointsView;
196 TilesAlpakaView<Ndim> tilesView;
197
198 ALPAKA_FN_ACC int32_t operator()(int32_t index) const {
199 float coords[Ndim];
200 for (auto dim = 0; dim < Ndim; ++dim) {
201 coords[dim] = pointsView.coords[index + dim * pointsView.n];
202 }
203
204 auto bin = tilesView.getGlobalBin(coords);
205 return bin;
206 }
207 };
208
209 template <concepts::accelerator TAcc, concepts::queue TQueue>
210 ALPAKA_FN_HOST void fill(TQueue& queue, PointsDevice<Ndim, TDev>& d_points, size_t size) {
211 auto dev = alpaka::getDev(queue);
212 auto pointsView = d_points.view();
213 m_assoc.template fill<TAcc>(size, GetGlobalBin{pointsView, m_view}, queue);
214 }
215
216 ALPAKA_FN_HOST inline clue::device_buffer<TDev, CoordinateExtremes<Ndim>> minMax() const {
217 return m_minmax;
218 }
219 ALPAKA_FN_HOST inline clue::device_buffer<TDev, float[Ndim]> tileSize() const {
220 return m_tilesizes;
221 }
222 ALPAKA_FN_HOST inline clue::device_buffer<TDev, uint8_t[Ndim]> wrapped() const {
223 return m_wrapped;
224 }
225
226 ALPAKA_FN_HOST inline constexpr auto size() const { return m_ntiles; }
227
228 ALPAKA_FN_HOST inline constexpr auto nPerDim() const { return m_nperdim; }
229
230 ALPAKA_FN_HOST inline constexpr auto extents() const { return m_assoc.extents(); }
231
232 template <concepts::queue TQueue>
233 ALPAKA_FN_HOST inline constexpr void clear(const TQueue& queue) {}
234
235 ALPAKA_FN_HOST const clue::device_buffer<TDev, int32_t[]>& indexes() const {
236 return m_assoc.indexes();
237 }
238 ALPAKA_FN_HOST clue::device_buffer<TDev, int32_t[]>& indexes() { return m_assoc.indexes(); }
239 ALPAKA_FN_HOST const clue::device_buffer<TDev, int32_t[]>& offsets() const {
240 return m_assoc.offsets();
241 }
242 ALPAKA_FN_HOST clue::device_buffer<TDev, int32_t[]>& offsets() { return m_assoc.offsets(); }
243
244 ALPAKA_FN_HOST clue::device_view<TDev, int32_t[]> indexes(const TDev& dev, size_t assoc_id) {
245 return m_assoc.indexes(dev, assoc_id);
246 }
247
248 private:
249 AssociationMap<TDev> m_assoc;
250 device_buffer<TDev, CoordinateExtremes<Ndim>> m_minmax;
251 device_buffer<TDev, float[Ndim]> m_tilesizes;
252 device_buffer<TDev, uint8_t[Ndim]> m_wrapped;
253 int32_t m_ntiles;
254 int32_t m_nperdim;
255 TilesAlpakaView<Ndim> m_view;
256 };
257
258} // namespace clue
Provides the AssociationMap class for managing associations between keys and values ///.
The AssociationMap class is a data structure that maps keys to values. It associates integer keys wit...
Definition AssociationMap.hpp:33
Definition Tiles.hpp:22
The PointsDevice class is a data structure that manages points on a device. It provides methods to al...
Definition PointsDevice.hpp:25
ALPAKA_FN_HOST const auto & view() const
Returns the view of the points.
Definition Tiles.hpp:40
Definition Tiles.hpp:194