OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
BinHisto.h
Go to the documentation of this file.
1#ifndef BIN_HISTO_H
2#define BIN_HISTO_H
3
4#include "BinningTools.h" // For postSum computation
5#include "Ippl.h"
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
61 template <
62 typename size_type, typename bin_index_type, typename value_type,
63 bool UseDualView = false, class... Properties>
64 class Histogram {
65 public:
66 // Histogram counts view type(s)
67 using view_type = std::conditional_t<
68 UseDualView, Kokkos::DualView<size_type*, Properties...>,
69 Kokkos::View<size_type*, Properties...>>;
72
73 // Histogram widths view type(s)
74 using width_view_type = std::conditional_t<
75 UseDualView, Kokkos::DualView<value_type*, Properties...>,
76 Kokkos::View<value_type*, Properties...>>;
79
80 // View types to map bin indices
81 template <class... Args>
82 using index_transform_type = Kokkos::View<bin_index_type*, Args...>;
84 Kokkos::DefaultExecutionSpace>; // Do not remove: needed inside
85 // AdaptBins::genAdaptiveHistogram()
87 // using hash_type =
88 // ippl::detail::hash_type<Kokkos::DefaultExecutionSpace::memory_space>;
89
93 Histogram() = default;
94
110 std::string debug_name, bin_index_type numBins, value_type totalBinWidth,
111 value_type binningAlpha, value_type binningBeta, value_type desiredWidth)
112 : debug_name_m(debug_name),
113 numBins_m(numBins),
114 totalBinWidth_m(totalBinWidth),
115 binningAlpha_m(binningAlpha),
116 binningBeta_m(binningBeta),
117 desiredWidth_m(desiredWidth) {
118 // Initialize the histogram, bin widths and post sum view
120 initTimers();
121 }
122
126 /*~Histogram() {
127 //std::cout << "Histogram " << debug_name_m << " destroyed." << std::endl;
128 } */
129
136 Histogram(const Histogram& other) { copyFields(other); }
137
145 if (this == &other) return *this;
146 copyFields(other);
147 return *this;
148 }
149
166 if constexpr (UseDualView) {
167 return histogram_m.view_host()(binIndex);
168 } else if (std::is_same<typename hview_type::memory_space, Kokkos::HostSpace>::value) {
169 return histogram_m(binIndex);
170 } else {
171 std::cerr << "Warning: Accessing BinHisto.getNPartInBin without DualView might be "
172 "inefficient!"
173 << std::endl;
174 Kokkos::View<size_type, Kokkos::HostSpace> host_scalar("host_scalar");
175 Kokkos::deep_copy(host_scalar, Kokkos::subview(histogram_m, binIndex));
176 return host_scalar();
177 }
178 }
179
184
190
195
201
212 template <typename Histogram_t>
213 void copyBinWidths(const Histogram_t& other) {
214 using other_dwidth_view_type = typename Histogram_t::dwidth_view_type;
215 Kokkos::deep_copy(
216 getDeviceView<dwidth_view_type>(binWidths_m),
217 other.template getDeviceView<other_dwidth_view_type>(other.getBinWidths()));
218 if constexpr (UseDualView) {
219 binWidths_m.modify_device();
220
221 IpplTimings::startTimer(bDeviceSyncronizationT);
222 binWidths_m.sync_host();
223 IpplTimings::stopTimer(bDeviceSyncronizationT);
224 }
225 }
226
233 void init() { // const value_type constBinWidth
234 // Assumes you have initialized histogram_m from the outside!
235 sync();
237 initPostSum();
238 }
239
248 void initConstBinWidths(const value_type constBinWidth) {
249 dwidth_view_type dWidthView = getDeviceView<dwidth_view_type>(binWidths_m);
250 const value_type binWidth = constBinWidth / numBins_m;
251 using execution_space = typename dwidth_view_type::execution_space;
252
253 IpplTimings::startTimer(bHistogramInitT);
254 // Note: "Kokkos::deep_copy(getDeviceView<dwidth_view_type>(binWidths_m), constBinWidth
255 // / numBins_m);" would work too!
256 Kokkos::parallel_for(
257 "InitConstBinWidths", Kokkos::RangePolicy<execution_space>(0, numBins_m),
258 KOKKOS_LAMBDA(const size_t i) { dWidthView(i) = binWidth; });
259 IpplTimings::stopTimer(bHistogramInitT);
260
261 if constexpr (UseDualView) {
262 binWidths_m.modify_device();
263 IpplTimings::startTimer(bDeviceSyncronizationT);
264 binWidths_m.sync_host();
265 IpplTimings::stopTimer(bDeviceSyncronizationT);
266 }
267 }
268
276 void initPostSum() {
277 IpplTimings::startTimer(bHistogramInitT);
278 computeFixSum<dview_type>(
279 getDeviceView<dview_type>(histogram_m), getDeviceView<dview_type>(postSum_m));
280 IpplTimings::stopTimer(bHistogramInitT);
281
282 if constexpr (UseDualView) {
283 postSum_m.modify_device();
284 IpplTimings::startTimer(bDeviceSyncronizationT);
285 postSum_m.sync_host();
286 IpplTimings::stopTimer(bDeviceSyncronizationT);
287 }
288 }
289
306 Kokkos::RangePolicy<> getBinIterationPolicy(
307 const bin_index_type& binIndex1, const bin_index_type numBins = 1) {
308 if constexpr (UseDualView) {
309 return Kokkos::RangePolicy<>(
310 postSum_m.view_host()(binIndex1),
311 postSum_m.view_host()(binIndex1 + numBins));
312 } else {
313 std::cerr << "Warning: Accessing BinHisto.getBinIterationPolicy without DualView "
314 "might be inefficient!"
315 << std::endl;
316 Kokkos::View<bin_index_type[2], Kokkos::HostSpace> host_ranges("host_scalar");
317 Kokkos::deep_copy(
318 host_ranges,
319 Kokkos::subview(postSum_m, std::make_pair(binIndex1, binIndex1 + numBins)));
320 return Kokkos::RangePolicy<>(host_ranges(0), host_ranges(1));
321 }
322 }
323
324 /*
325 Below are methods used for syncing the histogram view between host and device.
326 If a normal View is used, they have no effect.
327 Only necessary for the histogram view, since the binWidths and postSum views
328 are only modified inside this class.
329 */
330
342 void sync() {
343 IpplTimings::startTimer(bDeviceSyncronizationT);
344 if constexpr (UseDualView) {
345 if (histogram_m.need_sync_host() && histogram_m.need_sync_device()) {
346 std::cerr << "Warning: Histogram was modified on host AND device -- "
347 "overwriting changes on host."
348 << std::endl;
349 }
350 if (histogram_m.need_sync_host()) {
351 histogram_m.sync_host();
352 } else if (histogram_m.need_sync_device()) {
353 histogram_m.sync_device();
354 } // else do nothing
355 }
356 IpplTimings::stopTimer(bDeviceSyncronizationT);
357 }
358
366 if constexpr (UseDualView) histogram_m.modify_device();
367 }
368
375 void modify_host() {
376 if constexpr (UseDualView) histogram_m.modify_host();
377 }
378
391 template <typename return_type, typename HistogramType>
392 static constexpr return_type getDeviceView(HistogramType histo) {
393 if constexpr (UseDualView) {
394 return histo.view_device();
395 } else {
396 return histo;
397 }
398 }
399
410 template <typename return_type, typename HistogramType>
411 static constexpr return_type getHostView(HistogramType histo) {
412 if constexpr (UseDualView) {
413 return histo.view_host();
414 } else {
415 return histo;
416 }
417 }
418
454
455 private:
508 const size_type& sumCount, const value_type& sumWidth,
509 const size_type& totalNumParticles);
510
519 void initTimers() {
520 bDeviceSyncronizationT = IpplTimings::getTimer("bDeviceSyncronization");
521 bHistogramInitT = IpplTimings::getTimer("bHistogramInit");
522 bMergeBinsT = IpplTimings::getTimer("bMergeBins");
523 }
524
529 histogram_m = view_type("histogram", numBins_m);
530 binWidths_m = width_view_type("binWidths", numBins_m);
531 postSum_m = view_type("postSum", numBins_m + 1);
532 }
533
542 void copyFields(const Histogram& other);
543
544 private:
545 std::string debug_name_m;
548
555
560
561 IpplTimings::TimerRef bDeviceSyncronizationT;
562 IpplTimings::TimerRef bHistogramInitT;
563 IpplTimings::TimerRef bMergeBinsT;
564
565 /*
566 Here are just some debug functions, like a nice histogram output formatted as python numpy
567 arrays.
568 */
569 public:
575 void printHistogram(std::ostream& os = std::cout) {
576 if (ippl::Comm->rank() != 0) return;
577 hview_type countsHost = getHostView<hview_type>(histogram_m);
578 hwidth_view_type widthsHost = getHostView<hwidth_view_type>(binWidths_m);
579
580 // 3) Print header
581 os << "Histogram \"" << debug_name_m << "\" with " << numBins_m
582 << " bins. BinWidth = " << totalBinWidth_m << ".\n\n";
583
584 // Format columns: BinIndex, Count, Width
585 // Adjust widths as needed
586 os << std::left << std::setw(10) << "Bin" << std::right << std::setw(12) << "Count"
587 << std::setw(16) << "Width\n";
588
589 os << std::string(38, '-') << "\n";
590 // (38 dashes or however many you prefer to underline)
591
592 // 4) Print each bin
593 for (bin_index_type i = 0; i < numBins_m; ++i) {
594 os << std::left << std::setw(10) << i // bin index left-aligned
595 << std::right << std::setw(12) << countsHost(i) << std::fixed << std::setw(16)
596 << std::setprecision(6)
597 << static_cast<double>(widthsHost(i)) // in case 'value_type' is double/float
598 << "\n";
599 }
600
601 // os << "-----------------------------------------" << endl;
602 os << std::endl; // extra newline at the end
603 }
604
605 void printPythonArrays() const {
606 if (ippl::Comm->rank() != 0) return;
607 hview_type hostCounts = getHostView<hview_type>(histogram_m);
608 hwidth_view_type hostWidths = getHostView<hwidth_view_type>(binWidths_m);
609 // TODO: if I leave this here, it may need a deep_copy to make it save for every
610 // execution space
611
612 Inform msg("AdaptBins::printPythonArrays");
613
614 // Output counts as a Python NumPy array
615 msg << level5 << "bin_counts = np.array([";
616 for (bin_index_type i = 0; i < numBins_m; ++i) {
617 msg << level5 << hostCounts(i);
618 if (i < numBins_m - 1) msg << level5 << ", ";
619 }
620 msg << level5 << "])" << endl;
621
622 // Output widths as a Python NumPy array
623 msg << level5 << "bin_widths = np.array([";
624 for (bin_index_type i = 0; i < numBins_m; ++i) {
625 msg << level5 << std::fixed << std::setprecision(6) << hostWidths(i);
626 if (i < numBins_m - 1) msg << level5 << ", ";
627 }
628 msg << level5 << "])" << endl;
629 }
630 };
631
632} // namespace ParticleBinning
633
634#include "BinHisto.tpp"
635
636#endif // BIN_HISTO_H
ippl::detail::size_type size_type
TestT value_type
Container_t::bin_index_type bin_index_type
Template class providing adaptive particle histogram binning with support for Kokkos Views and DualVi...
Definition BinHisto.h:64
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:109
IpplTimings::TimerRef bMergeBinsT
Definition BinHisto.h:563
void printPythonArrays() const
Definition BinHisto.h:605
value_type binningBeta_m
Alpha parameter for the adaptive binning (merging) cost function.
Definition BinHisto.h:551
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:306
static constexpr return_type getHostView(HistogramType histo)
Retrieves a host view of the given histogram.
Definition BinHisto.h:411
Histogram()=default
Default constructor for the Histogram class.
Kokkos::View< bin_index_type *, Args... > index_transform_type
Definition BinHisto.h:82
value_type binningAlpha_m
Total width of all bins combined.
Definition BinHisto.h:549
view_type getHistogram() const
Definition BinHisto.h:189
view_type getHistogram()
Returns the Kokkos View containing the histogram bin counts.
Definition BinHisto.h:188
typename DeviceViewTraits< UseDualView, view_type >::h_type hview_type
Definition BinHisto.h:71
typename DeviceViewTraits< UseDualView, width_view_type >::h_type hwidth_view_type
Definition BinHisto.h:77
index_transform_type< Kokkos::DefaultExecutionSpace > dindex_transform_type
Definition BinHisto.h:84
value_type desiredWidth_m
Beta parameter for the adaptive binning (merging) cost function.
Definition BinHisto.h:553
size_type getNPartInBin(bin_index_type binIndex)
Retrieves the number of particles in a specified bin.
Definition BinHisto.h:165
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.
view_type postSum_m
View storing the widths of the bins.
Definition BinHisto.h:558
value_type totalBinWidth_m
Number of bins in the histogram.
Definition BinHisto.h:547
bin_index_type numBins_m
Debug name for identifying the histogram instance.
Definition BinHisto.h:546
void initPostSum()
Initializes and computes the post-sum for the histogram.
Definition BinHisto.h:276
void initConstBinWidths(const value_type constBinWidth)
Initializes the bin widths with a constant value.
Definition BinHisto.h:248
typename DeviceViewTraits< UseDualView, view_type >::d_type dview_type
Definition BinHisto.h:70
view_type getPostSum()
Returns the Kokkos View containing the post-sum of bin counts.
Definition BinHisto.h:194
IpplTimings::TimerRef bDeviceSyncronizationT
View storing the cumulative sum of bin counts (used in sorting, generating range policies).
Definition BinHisto.h:561
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:200
std::conditional_t< UseDualView, Kokkos::DualView< value_type *, Properties... >, Kokkos::View< value_type *, Properties... > > width_view_type
Definition BinHisto.h:76
view_type histogram_m
Desired width for the adaptive binning (merging) cost function.
Definition BinHisto.h:556
void sync()
Synchronizes the histogram data between host and device.
Definition BinHisto.h:342
void modify_host()
If a DualView is used, it sets the flag on the view that the host has been modified.
Definition BinHisto.h:375
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:213
width_view_type binWidths_m
View storing the particle counts in each bin.
Definition BinHisto.h:557
index_transform_type< Kokkos::HostSpace > hindex_transform_type
Definition BinHisto.h:86
void initTimers()
Initializes timers for various operations in the binning process.
Definition BinHisto.h:519
void modify_device()
If a DualView is used, it sets the flag on the view that the device has been modified.
Definition BinHisto.h:365
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:144
void init()
Synchronizes the histogram view and initializes the bin widths and post-sum.
Definition BinHisto.h:233
void instantiateHistograms()
Instantiates the histogram, bin widths, and post-sum views (Possibly DualView).
Definition BinHisto.h:528
static constexpr return_type getDeviceView(HistogramType histo)
Retrieves the device view of the histogram.
Definition BinHisto.h:392
IpplTimings::TimerRef bHistogramInitT
Definition BinHisto.h:562
typename DeviceViewTraits< UseDualView, width_view_type >::d_type dwidth_view_type
Definition BinHisto.h:78
std::conditional_t< UseDualView, Kokkos::DualView< size_type *, Properties... >, Kokkos::View< size_type *, Properties... > > view_type
Definition BinHisto.h:69
void printHistogram(std::ostream &os=std::cout)
Prints a nicely formatted table of bin indices, counts, and widths.
Definition BinHisto.h:575
size_type getCurrentBinCount() const
Returns the current number of bins in the histogram.
Definition BinHisto.h:183
Histogram(const Histogram &other)
Default destructor for the Histogram class.
Definition BinHisto.h:136
Traits class to extract host and device view types from a given ViewType.
Definition BinHisto.h:20