OPALX (Object Oriented Parallel Accelerator Library for Exascal) MINIorX
OPALX
BinHisto.h
Go to the documentation of this file.
1#ifndef BIN_HISTO_H
2#define BIN_HISTO_H
3
4#include "Ippl.h"
5#include "BinningTools.h" // For postSum computation
6
7#include <iomanip> // for std::setw, std::setprecision, etc. (debug output)
8
9namespace ParticleBinning {
10
19 template <bool UseDualView, typename ViewType>
21
25 template <typename ViewType>
26 struct DeviceViewTraits<true, ViewType> {
27 using h_type = typename ViewType::t_host;
28 using d_type = typename ViewType::t_dev;
29 };
30
34 template <typename ViewType>
35 struct DeviceViewTraits<false, ViewType> {
36 using h_type = ViewType;
37 using d_type = ViewType;
38 };
39
57 template <typename size_type, typename bin_index_type, typename value_type,
58 bool UseDualView = false, class... Properties>
59 class Histogram {
60 public:
61
62 // Histogram counts view type(s)
63 using view_type = std::conditional_t<UseDualView,
64 Kokkos::DualView<size_type*, Properties...>,
65 Kokkos::View<size_type*, Properties...>>;
68
69 // Histogram widths view type(s)
70 using width_view_type = std::conditional_t<UseDualView,
71 Kokkos::DualView<value_type*, Properties...>,
72 Kokkos::View<value_type*, Properties...>>;
75
76 // View types to map bin indices
77 template <class... Args>
78 using index_transform_type = Kokkos::View<bin_index_type*, Args...>;
79 using dindex_transform_type = index_transform_type<Kokkos::DefaultExecutionSpace>; // Do not remove: needed inside AdaptBins::genAdaptiveHistogram()
81 // using hash_type = ippl::detail::hash_type<Kokkos::DefaultExecutionSpace::memory_space>;
82
86 Histogram() = default;
87
98 Histogram(std::string debug_name, bin_index_type numBins, value_type totalBinWidth,
99 value_type binningAlpha, value_type binningBeta, value_type desiredWidth)
100 : debug_name_m(debug_name)
101 , numBins_m(numBins)
102 , totalBinWidth_m(totalBinWidth)
103 , binningAlpha_m(binningAlpha)
104 , binningBeta_m(binningBeta)
105 , desiredWidth_m(desiredWidth) {
106 // Initialize the histogram, bin widths and post sum view
108 initTimers();
109 }
110
114 /*~Histogram() {
115 //std::cout << "Histogram " << debug_name_m << " destroyed." << std::endl;
116 } */
117
123 Histogram(const Histogram& other) {
124 copyFields(other);
125 }
126
133 if (this == &other) return *this;
134 copyFields(other);
135 return *this;
136 }
137
152 size_type getNPartInBin(bin_index_type binIndex) {
153 if constexpr (UseDualView) {
154 return histogram_m.h_view(binIndex);
155 } else if (std::is_same<typename hview_type::memory_space, Kokkos::HostSpace>::value) {
156 return histogram_m(binIndex);
157 } else {
158 std::cerr << "Warning: Accessing BinHisto.getNPartInBin without DualView might be inefficient!" << std::endl;
159 Kokkos::View<size_type, Kokkos::HostSpace> host_scalar("host_scalar");
160 Kokkos::deep_copy(host_scalar, Kokkos::subview(histogram_m, binIndex));
161 return host_scalar();
162 }
163 }
164
169
174
179
185
194 template <typename Histogram_t>
195 void copyBinWidths(const Histogram_t& other) {
196 using other_dwidth_view_type = typename Histogram_t::dwidth_view_type;
198 other.template getDeviceView<other_dwidth_view_type>(other.getBinWidths()));
199 if constexpr (UseDualView) {
200 binWidths_m.modify_device();
201
202 IpplTimings::startTimer(bDeviceSyncronizationT);
203 binWidths_m.sync_host();
204 IpplTimings::stopTimer(bDeviceSyncronizationT);
205 }
206 }
207
208
214 void init() { // const value_type constBinWidth
215 // Assumes you have initialized histogram_m from the outside!
216 sync();
218 initPostSum();
219 }
220
221
229 void initConstBinWidths(const value_type constBinWidth) {
231 const value_type binWidth = constBinWidth / numBins_m;
232 using execution_space = typename dwidth_view_type::execution_space;
233
234 IpplTimings::startTimer(bHistogramInitT);
235 // Note: "Kokkos::deep_copy(getDeviceView<dwidth_view_type>(binWidths_m), constBinWidth / numBins_m);" would work too!
236 Kokkos::parallel_for("InitConstBinWidths",
237 Kokkos::RangePolicy<execution_space>(0, numBins_m), KOKKOS_LAMBDA(const size_t i) {
238 dWidthView(i) = binWidth;
239 }
240 );
241 IpplTimings::stopTimer(bHistogramInitT);
242
243 if constexpr (UseDualView) {
244 binWidths_m.modify_device();
245 IpplTimings::startTimer(bDeviceSyncronizationT);
246 binWidths_m.sync_host();
247 IpplTimings::stopTimer(bDeviceSyncronizationT);
248 }
249 }
250
251
258 void initPostSum() {
259 IpplTimings::startTimer(bHistogramInitT);
261 IpplTimings::stopTimer(bHistogramInitT);
262
263 if constexpr (UseDualView) {
264 postSum_m.modify_device();
265 IpplTimings::startTimer(bDeviceSyncronizationT);
266 postSum_m.sync_host();
267 IpplTimings::stopTimer(bDeviceSyncronizationT);
268 }
269 }
270
271
286 Kokkos::RangePolicy<> getBinIterationPolicy(const bin_index_type& binIndex1, const bin_index_type numBins = 1) {
287 if constexpr (UseDualView) {
288 return Kokkos::RangePolicy<>(postSum_m.h_view(binIndex1), postSum_m.h_view(binIndex1 + numBins));
289 } else {
290 std::cerr << "Warning: Accessing BinHisto.getBinIterationPolicy without DualView might be inefficient!" << std::endl;
291 Kokkos::View<bin_index_type[2], Kokkos::HostSpace> host_ranges("host_scalar");
292 Kokkos::deep_copy(host_ranges, Kokkos::subview(postSum_m, std::make_pair(binIndex1, binIndex1 + numBins)));
293 return Kokkos::RangePolicy<>(host_ranges(0), host_ranges(1));
294 }
295 }
296
297
298 /*
299 Below are methods used for syncing the histogram view between host and device.
300 If a normal View is used, they have no effect.
301 Only necessary for the histogram view, since the binWidths and postSum views
302 are only modified inside this class.
303 */
304
316 void sync() {
317 IpplTimings::startTimer(bDeviceSyncronizationT);
318 if constexpr (UseDualView) {
319 if (histogram_m.need_sync_host() && histogram_m.need_sync_device()) {
320 std::cerr << "Warning: Histogram was modified on host AND device -- overwriting changes on host." << std::endl;
321 }
322 if (histogram_m.need_sync_host()) {
323 histogram_m.sync_host();
324 } else if (histogram_m.need_sync_device()) {
325 histogram_m.sync_device();
326 } // else do nothing
327 }
328 IpplTimings::stopTimer(bDeviceSyncronizationT);
329 }
330
331
337 void modify_device() { if constexpr (UseDualView) histogram_m.modify_device(); }
338
339
345 void modify_host() { if constexpr (UseDualView) histogram_m.modify_host(); }
346
347
358 template <typename return_type, typename HistogramType>
359 static constexpr return_type getDeviceView(HistogramType histo) {
360 if constexpr (UseDualView) {
361 return histo.view_device();
362 } else {
363 return histo;
364 }
365 }
366
367
378 template <typename return_type, typename HistogramType>
379 static constexpr return_type getHostView(HistogramType histo) {
380 if constexpr (UseDualView) {
381 return histo.view_host();
382 } else {
383 return histo;
384 }
385 }
386
387
419
420 private:
470 const size_type& sumCount,
471 const value_type& sumWidth,
472 const size_type& totalNumParticles
473 );
474
475
484 void initTimers() {
485 bDeviceSyncronizationT = IpplTimings::getTimer("bDeviceSyncronization");
486 bHistogramInitT = IpplTimings::getTimer("bHistogramInit");
487 bMergeBinsT = IpplTimings::getTimer("bMergeBins");
488 }
489
490
495 histogram_m = view_type("histogram", numBins_m);
496 binWidths_m = width_view_type("binWidths", numBins_m);
497 postSum_m = view_type("postSum", numBins_m + 1);
498 }
499
500
509 void copyFields(const Histogram& other);
510
511 private:
512 std::string debug_name_m;
513 bin_index_type numBins_m;
514 value_type totalBinWidth_m;
515
516 value_type binningAlpha_m;
517 value_type binningBeta_m;
518 value_type desiredWidth_m;
519
523
524 IpplTimings::TimerRef bDeviceSyncronizationT;
525 IpplTimings::TimerRef bHistogramInitT;
526 IpplTimings::TimerRef bMergeBinsT;
527
528
529 /*
530 Here are just some debug functions, like a nice histogram output formatted as python numpy arrays.
531 */
532 public:
538 void printHistogram(std::ostream &os = std::cout) {
539 if (ippl::Comm->rank() != 0) return;
542
543 // 3) Print header
544 os << "Histogram \"" << debug_name_m << "\" with " << numBins_m << " bins. BinWidth = " << totalBinWidth_m << ".\n\n";
545
546 // Format columns: BinIndex, Count, Width
547 // Adjust widths as needed
548 os << std::left
549 << std::setw(10) << "Bin"
550 << std::right
551 << std::setw(12) << "Count"
552 << std::setw(16) << "Width\n";
553
554 os << std::string(38, '-') << "\n";
555 // (38 dashes or however many you prefer to underline)
556
557 // 4) Print each bin
558 for (bin_index_type i = 0; i < numBins_m; ++i) {
559 os << std::left << std::setw(10) << i // bin index left-aligned
560 << std::right << std::setw(12) << countsHost(i)
561 << std::fixed << std::setw(16) << std::setprecision(6)
562 << static_cast<double>(widthsHost(i)) // in case 'value_type' is double/float
563 << "\n";
564 }
565
566 //os << "-----------------------------------------" << endl;
567 os << std::endl; // extra newline at the end
568 }
569
570 void printPythonArrays() const {
571 if (ippl::Comm->rank() != 0) return;
574 // TODO: if I leave this here, it may need a deep_copy to make it save for every execution space
575
576 // Output counts as a Python NumPy array
577 std::cout << "bin_counts = np.array([";
578 for (bin_index_type i = 0; i < numBins_m; ++i) {
579 std::cout << hostCounts(i);
580 if (i < numBins_m - 1) std::cout << ", ";
581 }
582 std::cout << "])" << std::endl;
583
584 // Output widths as a Python NumPy array
585 std::cout << "bin_widths = np.array([";
586 for (bin_index_type i = 0; i < numBins_m; ++i) {
587 std::cout << std::fixed << std::setprecision(6) << hostWidths(i);
588 if (i < numBins_m - 1) std::cout << ", ";
589 }
590 std::cout << "])" << std::endl;
591 }
592
593 };
594
595}
596
597#include "BinHisto.tpp"
598
599#endif // BIN_HISTO_H
ippl::detail::size_type size_type
void computeFixSum(const ViewType &input_view, const ViewType &post_sum_view)
Computes the post- or prefix-sum of the input view and stores the result in the .....
Traits class to extract host and device view types from a given ViewType.
Definition BinHisto.h:20
Histogram(std::string debug_name, bin_index_type numBins, value_type totalBinWidth, value_type binningAlpha, value_type binningBeta, value_type desiredWidth)
Constructor for the Histogram class with a given name, number of bins, and total bin width.
Definition BinHisto.h:98
void printPythonArrays() const
Definition BinHisto.h:570
std::conditional_t< UseDualView, Kokkos::DualView< size_type *, Properties... >, Kokkos::View< size_type *, Properties... > > view_type
Definition BinHisto.h:63
Kokkos::RangePolicy getBinIterationPolicy(const bin_index_type &binIndex1, const bin_index_type numBins=1)
Returns a Kokkos::RangePolicy for iterating over the elements in a specified bin.
Definition BinHisto.h:286
static constexpr return_type getHostView(HistogramType histo)
Retrieves a host view of the given histogram.
Definition BinHisto.h:379
std::conditional_t< UseDualView, Kokkos::DualView< value_type *, Properties... >, Kokkos::View< value_type *, Properties... > > width_view_type
Definition BinHisto.h:70
Histogram()=default
Default constructor for the Histogram class.
Kokkos::View< bin_index_type *, Args... > index_transform_type
Definition BinHisto.h:78
view_type getHistogram()
Returns the Kokkos View containing the histogram bin counts.
Definition BinHisto.h:173
typename DeviceViewTraits< UseDualView, view_type >::h_type hview_type
Definition BinHisto.h:67
typename DeviceViewTraits< UseDualView, width_view_type >::h_type hwidth_view_type
Definition BinHisto.h:73
size_type getNPartInBin(bin_index_type binIndex)
Retrieves the number of particles in a specified bin.
Definition BinHisto.h:152
value_type adaptiveBinningCostFunction(const size_type &sumCount, const value_type &sumWidth, const size_type &totalNumParticles)
Computes the cost function for adaptive binning in a histogram.
void initPostSum()
Initializes and computes the post-sum for the histogram.
Definition BinHisto.h:258
void initConstBinWidths(const value_type constBinWidth)
Initializes the bin widths with a constant value.
Definition BinHisto.h:229
typename DeviceViewTraits< UseDualView, view_type >::d_type dview_type
Definition BinHisto.h:66
view_type getPostSum()
Returns the Kokkos View containing the post-sum of bin counts.
Definition BinHisto.h:178
index_transform_type< Kokkos::DefaultExecutionSpace > dindex_transform_type
Definition BinHisto.h:79
hindex_transform_type mergeBins()
Merges bins in a histogram to reduce the number of bins while minimizing a cost function.
width_view_type getBinWidths() const
Returns the Kokkos View of bin widths in the current histogram configuration. It will be an array of ...
Definition BinHisto.h:184
void sync()
Synchronizes the histogram data between host and device.
Definition BinHisto.h:316
void modify_host()
If a DualView is used, it sets the flag on the view that the host has been modified.
Definition BinHisto.h:345
void copyBinWidths(const Histogram_t &other)
Sets the bin widths by copying them from a different Histogram instance (usually neccessary after mer...
Definition BinHisto.h:195
index_transform_type< Kokkos::HostSpace > hindex_transform_type
Definition BinHisto.h:80
void initTimers()
Initializes timers for various operations in the binning process.
Definition BinHisto.h:484
void modify_device()
If a DualView is used, it sets the flag on the view that the device has been modified.
Definition BinHisto.h:337
void copyFields(const Histogram &other)
Copies the fields from another Histogram object.
Histogram & operator=(const Histogram &other)
Assignment operator for copying the fields from another Histogram object.
Definition BinHisto.h:132
void init()
Synchronizes the histogram view and initializes the bin widths and post-sum.
Definition BinHisto.h:214
void instantiateHistograms()
Instantiates the histogram, bin widths, and post-sum views (Possibly DualView).
Definition BinHisto.h:494
static constexpr return_type getDeviceView(HistogramType histo)
Definition BinHisto.h:359
typename DeviceViewTraits< UseDualView, width_view_type >::d_type dwidth_view_type
Definition BinHisto.h:74
void printHistogram(std::ostream &os=std::cout)
Prints a nicely formatted table of bin indices, counts, and widths.
Definition BinHisto.h:538
size_type getCurrentBinCount() const
Returns the current number of bins in the histogram.
Definition BinHisto.h:168
Histogram(const Histogram &other)
Default destructor for the Histogram class.
Definition BinHisto.h:123