yoda is hosted by Hepforge, IPPP Durham
YODA - Yet more Objects for Data Analysis 2.0.0
Binning.h
Go to the documentation of this file.
1// -*- C++ -*-
2//
3// This file is part of YODA -- Yet more Objects for Data Analysis
4// Copyright (C) 2008-2023 The YODA collaboration (see AUTHORS for details)
5//
6#ifndef YODA_BINNING_H
7#define YODA_BINNING_H
8#include "YODA/BinnedAxis.h"
10#include <memory>
11#include <tuple>
12#include <vector>
13#include <array>
14
15namespace YODA {
16
18 template<typename CoordT>
19 double nullifyIfDiscCoord(CoordT&& /* coord */, std::false_type, double null = 0.0) {
20 return null;
21 }
22 //
23 template<typename CoordT>
24 double nullifyIfDiscCoord(CoordT&& coord, std::true_type, double /* null */ = 0.0) {
25 return std::forward<CoordT>(coord);
26 }
27
29 template<typename... Args>
30 inline bool containsNan(const std::tuple<Args...>& coords) {
31 std::array<size_t, sizeof...(Args)> hasNan{};
32 auto checkCoords = [&hasNan, &coords](auto I) {
33 using isContinuous = typename std::is_floating_point<typename std::tuple_element_t<I, std::tuple<Args...>>>;
34
35 hasNan[I] = size_t(std::isnan(nullifyIfDiscCoord(std::move(std::get<I>(coords)),
36 std::integral_constant<bool,
37 isContinuous::value>{})));
38 };
39
40 MetaUtils::staticFor<sizeof...(Args)>(checkCoords);
41
42 return std::any_of(hasNan.begin(), hasNan.end(), [ ](const bool i) { return i; } );
43 }
44
45
46
47 template <typename... Axes>
48 class Binning {
49 private:
50
51 std::tuple<Axes...> _axes;
52 size_t _dim = sizeof...(Axes);
53 std::vector<size_t> _maskedIndices;
54
55
56 protected:
57
59 // @{
60
61 using IndexArr = std::array<size_t, sizeof...(Axes)>;
62
63 // @}
64
65 public:
66
68 // @{
69
70 template <size_t I>
71 using getAxisT = std::tuple_element_t<I, std::tuple<Axes...>>;
72
73 template <size_t I>
74 using getEdgeT = typename getAxisT<I>::EdgeT;
75
76 template <size_t I>
77 using is_CAxis = typename std::is_floating_point<getEdgeT<I>>;
78
79 template<size_t I>
80 using is_Arithmetic = typename std::is_arithmetic<getEdgeT<I>>;
81
82 using all_CAxes = typename std::conjunction<std::is_floating_point<typename Axes::EdgeT>...>;
83
84 using EdgeTypesTuple = decltype(
85 std::tuple_cat(std::declval<std::tuple<typename Axes::EdgeT>>()...));
86
87 using Dimension = std::integral_constant<size_t, sizeof...(Axes)>;
88
89 // @}
90
92
93
95 Binning() { }
96
98 Binning(const std::initializer_list<typename Axes::EdgeT>&... edges)
99 : _axes(Axes(edges)...) {
101 }
102
104 Binning(std::initializer_list<typename Axes::EdgeT>&&... edges)
105 : _axes(Axes(std::move(edges))...) {
107 }
108
110 Binning(const Axes&... axes)
111 : _axes(axes...) {
113 }
114
116 Binning(Axes&&... axes)
117 : _axes(std::move(axes)...) {
119 }
120
122 Binning(const Binning& other) : _axes(other._axes), _maskedIndices(other._maskedIndices) {}
123
125 Binning(Binning&& other) : _axes(std::move(other._axes)), _maskedIndices(std::move(other._maskedIndices)) {}
126
128 Binning& operator=(const Binning& other) {
129 if (this != &other) {
130 _axes = other._axes;
131 _maskedIndices = other._maskedIndices;
132 }
133 return *this;
134 }
135
138 if (this != &other) {
139 _axes = std::move(other._axes);
140 _maskedIndices = std::move(other._maskedIndices);
141 }
142 return *this;
143 }
144
146
148
149
151 size_t localToGlobalIndex(const IndexArr& localIndices) const;
152
154 IndexArr globalToLocalIndices(size_t globalIndex) const;
155
157 IndexArr localIndicesAt(const EdgeTypesTuple& coords) const;
158
160 size_t globalIndexAt(const EdgeTypesTuple& coords) const;
161
163 std::vector<size_t> calcOverflowBinsIndices() const noexcept;
164
166 size_t countOverflowBins(const size_t axisN) const noexcept;
167
169 std::vector<size_t> maskedBins() const noexcept { return _maskedIndices; }
170
172 void clearMaskedBins() noexcept { _maskedIndices.clear(); }
173
175 void maskBin(const size_t index, const bool status = true);
176
178 void maskBin(const IndexArr& localIndices, const bool status = true);
179
181 void maskBinAt(const EdgeTypesTuple& coords, const bool status = true) noexcept;
182
184 void maskBins(const std::vector<size_t>& indices, const bool status = true);
185
187 void maskSlice(const size_t dim, const size_t idx, const bool status = true);
188
190 bool isMasked(const size_t i) const noexcept;
191
193 bool isVisible(const size_t i) const noexcept;
194
196 size_t calcSliceSize(const size_t pivotAxisN) const noexcept;
197
201 std::vector<size_t> sliceIndices(std::vector<std::pair<size_t, std::vector<size_t>>>) const noexcept;
202
205 std::vector<size_t> sliceIndices(size_t axisN, size_t binN) const noexcept;
206
209 void updateMaskedBins() noexcept {
210
211 std::vector<std::pair<size_t, std::vector<size_t>>> slicePivots;
212 auto extractMaskedBins = [&slicePivots, &axes = _axes](auto I) {
213 using isContinuous = typename Binning::template is_CAxis<I>;
214
215 if constexpr(isContinuous::value) {
216 const auto& axis = std::get<I>(axes);
217 slicePivots.push_back({I, {axis.maskedBins()} });
218 }
219 };
220
221 // apply for all axes
222 MetaUtils::staticFor<Dimension::value>(extractMaskedBins);
223
224 // get indices along slice pivots and remove duplicates
225 _maskedIndices = sliceIndices(slicePivots);
226 std::sort(_maskedIndices.begin(), _maskedIndices.end());
227 _maskedIndices.erase( std::unique(_maskedIndices.begin(), _maskedIndices.end()),
228 _maskedIndices.end() );
229 }
230
232
234
235 // @{
236 template <size_t... AxisNs>
237 void mergeBins(
238 std::decay_t<decltype(AxisNs, std::declval<std::pair<size_t, size_t>>())>... mergeRanges) noexcept;
239 // @}
240
242
243
248 bool isCompatible(const Binning<Axes...>& other) const noexcept;
249
251
253
254
256 template <size_t I>
257 const getAxisT<I>& axis() const noexcept;
258
260 template <size_t I>
261 getAxisT<I>& axis() noexcept;
262
263 template<size_t I>
264 auto _getAxesExcept() const noexcept;
265
267 IndexArr _getAxesSizes(const bool includeOverflows = true) const noexcept;
268
270 size_t dim() const noexcept;
271
273 size_t numBins(const bool includeOverflows = true, const bool includeMaskedBins = true) const noexcept;
274
276 size_t numBinsAt(const size_t axisN, const bool includeOverflows = true) const noexcept;
277
279 EdgeTypesTuple edgeTuple(const size_t index) const noexcept;
280
285 template <size_t I, typename E = getEdgeT<I>>
286 std::vector<E> edges(const bool includeOverflows = false) const noexcept {
287 const auto& axis = std::get<I>(_axes);
288 if (!includeOverflows && Binning::template is_CAxis<I>::value) {
289 auto&& all_edges = axis.edges();
290 typename std::vector<E> rtn;
291 const size_t offset = all_edges.size() - 1;
292 rtn.insert(rtn.end(), std::make_move_iterator(all_edges.begin()+1),
293 std::make_move_iterator(all_edges.begin()+offset));
294 return rtn;
295 }
296 return axis.edges();
297 }
298
305 template <size_t I, typename E = getEdgeT<I>>
306 std::enable_if_t<std::is_floating_point<E>::value, std::vector<E>>
307 widths(const bool includeOverflows = false) const noexcept {
308 const auto& axis = std::get<I>(_axes);
309 return axis.widths(includeOverflows);
310 }
311
315 template <size_t I, typename E = getEdgeT<I>>
316 std::enable_if_t<std::is_floating_point<E>::value, E> min() const noexcept {
317 const auto& axis = std::get<I>(_axes);
318 assert(axis.numBins(true) > 2); // More than 2 overflow bins.
319 return axis.min(1); // Bin 0 is the underflow bin.
320 }
321
325 template <size_t I, typename E = getEdgeT<I>>
326 std::enable_if_t<std::is_floating_point<E>::value, E> max() const noexcept {
327 const auto& axis = std::get<I>(_axes);
328 assert(axis.numBins(true) > 2); // More than 2 overflow bins.
329 return axis.min(axis.numBins(true)-1); // Bin 0 is the underflow bin.
330 }
331
333 double dVol(const size_t index) const;
334
336
339
341 void _renderYODA(std::ostream& os) const noexcept {
342 // lambda that renders the axis edges
343 auto edgePrinter = [&](auto I) {
344 const auto& axis = std::get<I>(_axes);
345 if (axis.numBins()) {
346 os << "Edges(A"+ std::to_string(I+1) + "): ";
347 axis._renderYODA(os);
348 os << "\n";
349 }
350 };
351 // apply lambda to all axes
352 MetaUtils::staticFor<Dimension::value>(edgePrinter);
353
354 // render indices of masked bins
355 if (_maskedIndices.size()) {
356 std::vector<size_t> gaps(_maskedIndices.size());
357 std::partial_sort_copy(begin(_maskedIndices), end(_maskedIndices), begin(gaps), end(gaps));
358 //std::sort(_maskedIndices.begin(), _maskedIndices.end());
359 os << "MaskedBins: [";
360 for (size_t i = 0; i < gaps.size(); ++i) {
361 if (i) os << ", ";
362 os << std::to_string(gaps[i]);
363 }
364 os << "]\n";
365 }
366 }
367
369 void _renderYODA(std::ostream& os, const size_t idx, const int width = 13) const {
370 IndexArr localIndices = globalToLocalIndices(idx);
371 // lambda that renders low/high edge or discrete value depending on the axis type
372 auto edgePrinter = [&](auto I) {
373 const auto& axis = std::get<I>(_axes);
374 axis._renderYODA(os, localIndices[I], width);
375 };
376 // apply lambda to all axes
377 MetaUtils::staticFor<Dimension::value>(edgePrinter);
378 }
379
381
382 };
383
384
385 template<typename... Axes>
386 size_t Binning<Axes...>::localToGlobalIndex(const IndexArr& localIndices) const {
387 size_t gIndex = 0;
388 // std::string st_indices = "";
389 // for (size_t iIndex = 0; iIndex < localIndices.size(); ++iIndex) {
390 // st_indices += "|";
391 // st_indices += std::to_string(localIndices[iIndex]);
392 // }
393
395 IndexArr axesSizes = _getAxesSizes();
396 for (size_t iIndex = 0; iIndex < localIndices.size(); ++iIndex) {
397 size_t productOfBinSizes = 1;
398 for (ssize_t iBinnedAxis = iIndex - 1; iBinnedAxis >= 0; --iBinnedAxis) {
399 productOfBinSizes *= (axesSizes[iBinnedAxis]);
400 }
401 gIndex += localIndices[iIndex] * productOfBinSizes;
402 }
403 return gIndex;
404 }
405
406 template <typename... Axes>
407 typename Binning<Axes...>::IndexArr
408 Binning<Axes...>::globalToLocalIndices(size_t globalIndex) const {
409 if (globalIndex >= numBins(true, true)) throw RangeError("Global index outside bin range");
410 IndexArr localIndices{};
411
412 IndexArr axesSizes = _getAxesSizes();
413
414 for (ssize_t iIndex = localIndices.size()-1 ; iIndex >= 0; --iIndex){
415 size_t productOfNestedBinSizes = 1;
416
417 for (ssize_t iBinnedAxis = iIndex - 1; iBinnedAxis >= 0; --iBinnedAxis) {
418 productOfNestedBinSizes *= (axesSizes[iBinnedAxis]);
419 }
420
421 // integer division to get the multiplier
422 localIndices[iIndex] = globalIndex / productOfNestedBinSizes;
423 // then left with only the remainder
424 globalIndex = globalIndex % productOfNestedBinSizes;
425 }
426 return localIndices;
427 }
428
429 template<typename... Axes>
430 typename Binning<Axes...>::IndexArr
432 IndexArr localIndices{};
433 auto extractIndices = [&localIndices, &coords, &axes = _axes](auto I) {
434 const auto& coord = std::get<I>(coords);
435 const auto& axis = std::get<I>(axes);
436
437 localIndices[I] = axis.index(coord);
438 };
439
440 MetaUtils::staticFor<Dimension::value>(extractIndices);
441
442 return localIndices;
443 }
444
445 template<typename... Axes>
447 return localToGlobalIndex(localIndicesAt(coords));
448 }
449
450 template<typename... Axes>
451 std::vector<size_t> Binning<Axes...>::calcOverflowBinsIndices() const noexcept {
452 IndexArr axesSizes = _getAxesSizes();
453 std::vector<bool> isCAxis;
454
455 auto getCAxisIndices = [&isCAxis](auto I){
456 using isContinuous = typename Binning::template is_CAxis<I>;
457 isCAxis.emplace_back(isContinuous::value);
458 };
459
460 MetaUtils::staticFor<Dimension::value>(getCAxisIndices);
461
462 std::vector<std::pair<size_t, std::vector<size_t>>> slicePivots;
463 slicePivots.reserve(isCAxis.size());
464
465 for (size_t axisN = 0; axisN < isCAxis.size(); ++axisN) {
466 if (isCAxis[axisN])
467 slicePivots.push_back({axisN, {0, axesSizes[axisN]-1} });
468 else
469 slicePivots.push_back({axisN, {0} });
470 }
471
472 std::vector<size_t> res = sliceIndices(slicePivots);
473 std::sort(res.begin(), res.end());
474 res.erase( std::unique(res.begin(), res.end()), res.end() );
475 return res;
476 }
477
478
484 template<typename... Axes>
485 size_t Binning<Axes...>::countOverflowBins(const size_t axisN) const noexcept {
486 std::vector<bool> CAxisIndices;
487
488 auto getCAxisIndices = [&CAxisIndices](auto I){
489 using isContinuous = typename Binning::template is_CAxis<I>;
490 CAxisIndices.emplace_back(isContinuous::value);
491 };
492
493 MetaUtils::staticFor<Dimension::value>(getCAxisIndices);
494 return CAxisIndices.at(axisN) + 1;
495 }
496
498 /*namespace {
499 template<typename VecT, typename AxisT, typename IdxT>
500 void appendIfCAxis(VecT& vec, AxisT& axis, IdxT I, std::true_type) {
501 if(axis.maskedBins.size() != 0)
502 vec.push_back({I, axis.maskedBins});
503 }
504
505 template<typename VecT, typename AxisT, typename IdxT>
506 void appendIfCAxis(VecT& vec, AxisT& axis, IdxT I, std::false_type) {
507 return;
508 }
509 }*/
510
511 template<typename... Axes>
512 void Binning<Axes...>::maskBin(const size_t index, const bool status) {
513 Binning<Axes...>::maskBins({{index}}, status);
514 }
515
516 template<typename... Axes>
517 void Binning<Axes...>::maskBin(const IndexArr& localIndices, const bool status) {
518 const size_t gIndex = Binning<Axes...>::localToGlobalIndex(localIndices);
519 Binning<Axes...>::maskBins({{gIndex}}, status);
520 }
521
522 template<typename... Axes>
523 void Binning<Axes...>::maskBinAt(const EdgeTypesTuple& coords, const bool status) noexcept {
524 const size_t gIndex = Binning<Axes...>::globalIndexAt(coords);
525 Binning<Axes...>::maskBins({{gIndex}}, status);
526 }
527
528 template<typename... Axes>
529 void Binning<Axes...>::maskBins(const std::vector<size_t>& indices, const bool status) {
530 for (size_t i : indices) {
531 const auto& itEnd = this->_maskedIndices.cend();
532 const auto& res = std::find(this->_maskedIndices.cbegin(), itEnd, i);
533 if (status && res == itEnd) this->_maskedIndices.push_back(i);
534 else if (!status && res != itEnd) this->_maskedIndices.erase(res);
535 }
536 }
537
538 template <typename... Axes>
539 void Binning<Axes...>::maskSlice(const size_t dim, const size_t idx, const bool status) {
540 //_binning.maskSlice(dim, idx, status);
541 std::vector<std::pair<size_t, std::vector<size_t>>> slicePivot{{dim,{idx}}};
542 std::vector<size_t> indices = Binning<Axes...>::sliceIndices(slicePivot);
543 Binning<Axes...>::maskBins(indices, status);
544 }
545
546 template<typename... Axes>
547 bool Binning<Axes...>::isMasked(const size_t i) const noexcept {
548 const auto& itEnd = _maskedIndices.cend();
549 return std::find(_maskedIndices.cbegin(), itEnd, i) != itEnd;
550 }
551
552 // @todo Should this also check if the bin is masked?
553 template<typename... Axes>
554 bool Binning<Axes...>::isVisible(const size_t i) const noexcept {
555 const std::vector<size_t> overflows = calcOverflowBinsIndices();
556 const auto& itEnd = overflows.cend();
557 return std::find(overflows.cbegin(), itEnd, i) == itEnd;
558 }
559
560 template<typename... Axes>
561 size_t Binning<Axes...>::calcSliceSize(const size_t pivotAxisN) const noexcept {
562 const IndexArr axesSizes = _getAxesSizes();
563 size_t sliceSize = 1;
564 for (size_t iDim = 0; iDim < _dim; ++iDim) {
565 if (iDim == pivotAxisN)
566 continue;
567 sliceSize *= (axesSizes[iDim]);
568 }
569 return sliceSize;
570 }
571
572 template<typename... Axes>
573 std::vector<size_t>
574 Binning<Axes...>::sliceIndices(std::vector<std::pair<size_t, std::vector<size_t>>> slicePivots) const noexcept {
575
576 std::vector<size_t> slicesSizes;
577 slicesSizes.reserve(slicePivots.size());
578 size_t slicedIndicesVecSize = 0;
579
580 for (const auto& slicePivot : slicePivots) {
581 if(slicePivot.second.size() == 0)
582 continue;
583
584 const size_t& sliceSize = calcSliceSize(slicePivot.first);
585
586 slicesSizes.emplace_back(sliceSize);
587 slicedIndicesVecSize += sliceSize;
588 }
589
590 std::vector<size_t> slicedIndices;
591 slicedIndices.reserve(slicedIndicesVecSize);
592
593 auto appendSliceIndices = [&slicedIndices](std::vector<size_t>&& overflowSlice) {
594 slicedIndices.insert(std::end(slicedIndices),
595 std::make_move_iterator(std::begin(overflowSlice)),
596 std::make_move_iterator(std::end(overflowSlice)));
597 };
598
599 for (const auto& slicePivot : slicePivots) {
600 const size_t axisN = slicePivot.first;
601 const auto& binPivots = slicePivot.second;
602
603 for(const auto& binPivot : binPivots) {
604 appendSliceIndices(sliceIndices(axisN, binPivot));
605 }
606 }
607
608 return slicedIndices;
609 }
610
611 template<typename... Axes>
612 std::vector<size_t> Binning<Axes...>::sliceIndices(const size_t axisN, const size_t binN) const noexcept {
613 if(sizeof...(Axes) == 1) {
614 return {binN};
615 }
617 const IndexArr axesSizes = _getAxesSizes();
618 const size_t sliceSize = calcSliceSize(axisN);
619
620 IndexArr multiIdx{};
621 multiIdx[axisN] = binN;
622 std::vector<size_t> slicedIndices;
623
624 assert(axesSizes.size() != 0);
625 slicedIndices.reserve(sliceSize);
626
627 /* @note Iteratively generates permutations of multindex for fixed
633 */
634 size_t idxShift = axisN == 0 ? 1 : 0;
635
636 size_t idx = idxShift;
637
638 while (true) {
639 slicedIndices.emplace_back(localToGlobalIndex(multiIdx));
640
641 multiIdx[idx]++;
642
643 while (multiIdx[idx] == axesSizes[idx] || idx == axisN) {
644 // Overflow, we're done
645 if (idx == axesSizes.size() - 1) {
646 return slicedIndices;
647 }
648
649 if(idx != axisN)
650 multiIdx[idx] = 0;
651
652 idx++;
653
654 if(idx != axisN)
655 multiIdx[idx]++;
656 }
657
658 idx = idxShift;
659 }
660
661 return slicedIndices;
662 }
663
664 template <typename... Axes>
665 template <size_t... AxisNs>
667 std::decay_t<decltype(AxisNs, std::declval<std::pair<size_t, size_t>>())>... mergeRanges) noexcept {
668
669 ((void)axis<AxisNs>().mergeBins(mergeRanges), ...);
670 updateMaskedBins();
671
672 }
673
674
675 template <typename... Axes>
676 template <size_t I>
677 const typename Binning<Axes...>::template getAxisT<I>&
678 Binning<Axes...>::axis() const noexcept {
679 return std::get<I>(_axes);
680 }
681
682 template <typename... Axes>
683 template <size_t I>
684 typename Binning<Axes...>::template getAxisT<I>&
686 return std::get<I>(_axes);
687 }
688
689
690 template<typename... Axes>
691 template<size_t I>
692 auto Binning<Axes...>::_getAxesExcept() const noexcept {
693 return MetaUtils::removeTupleElement<I>(_axes);
694 }
695
696 template<typename... Axes>
697 typename Binning<Axes...>::IndexArr
698 Binning<Axes...>::_getAxesSizes(const bool includeOverflows) const noexcept {
699 IndexArr axesSizes{};
700 auto extractSizes = [&axesSizes, &axes = _axes, &includeOverflows](auto I) {
701 const auto& axis = std::get<I>(axes);
702 axesSizes[I] = axis.numBins(includeOverflows);
703 };
704
705 MetaUtils::staticFor<Dimension::value>(extractSizes);
706
707 return axesSizes;
708 }
709
710 template<typename... Axes>
711 size_t Binning<Axes...>::dim() const noexcept {
712 return _dim;
713 }
714
715
716 template<typename... Axes>
717 bool Binning<Axes...>::isCompatible(const Binning<Axes...>& other) const noexcept {
718 // compatible if they have the same number of axes,
719 // and those axes have the same bin edges
720 if (_dim != other.dim())
721 return false;
722
723 std::array<bool, 1> isEqual{true};
724 auto isEqAxes =
725 [&isEqual, &axes1 = _axes, &axes2 = other._axes](auto I) {
726 const auto& axis_lhs = std::get<I>(axes1);
727 const auto& axis_rhs = std::get<I>(axes2);
728
730 isEqual[0] &= axis_lhs.hasSameEdges(axis_rhs);
731 };
732
733 MetaUtils::staticFor<Dimension::value>(isEqAxes);
734
735 return isEqual[0];
736 }
737
738 template<typename... Axes>
739 size_t Binning<Axes...>::numBins(const bool includeOverflows, const bool includeMaskedBins) const noexcept {
740 size_t nBins = 0;
741 IndexArr axesSizes = _getAxesSizes(includeOverflows);
742 assert(axesSizes.size() > 0);
743 nBins = axesSizes[0];
744 if constexpr (sizeof...(Axes) > 1) {
745 for (size_t iDim = 1; iDim < _dim; ++iDim) {
746 nBins *= (axesSizes[iDim]);
747 }
748 }
749 const size_t maskedBins = includeMaskedBins? 0 : _maskedIndices.size();
750 return nBins - maskedBins;
751 }
752
753 template<typename... Axes>
754 size_t Binning<Axes...>::numBinsAt(const size_t axisN, const bool includeOverflows) const noexcept {
755 IndexArr axesSizes = _getAxesSizes(includeOverflows);
756 assert(axesSizes.size() > 0);
757 return axesSizes[axisN];
758 }
759
760 template<typename... Axes>
761 typename Binning<Axes...>::EdgeTypesTuple
762 Binning<Axes...>::edgeTuple(const size_t index) const noexcept {
763
764 EdgeTypesTuple coords;
765 IndexArr indices = globalToLocalIndices(index);
766
767 auto setCoords = [&coords, &indices, &axes = _axes](auto I) {
768 using isContinuous = typename Binning::template is_CAxis<I>;
769 const auto& axis = std::get<I>(axes);
770 const size_t idx = std::get<I>(indices);
771 if constexpr(isContinuous::value) {
772 std::get<I>(coords) = axis.mid(idx);
773 }
774 else {
775 std::get<I>(coords) = axis.edge(idx);
776 }
777 };
778 MetaUtils::staticFor<Dimension::value>(setCoords);
779
780 return coords;
781 }
782
783 template<typename... Axes>
784 double Binning<Axes...>::dVol(const size_t index) const {
785 double rtn = 1.0;
786 IndexArr indices = globalToLocalIndices(index);
787
788 auto getCAxisWidths = [&rtn, &indices, &axes = _axes](auto I){
789 using isContinuous = typename Binning::template is_CAxis<I>;
790 if constexpr (isContinuous::value) {
791 const auto& axis = std::get<I>(axes);
792 const size_t idx = std::get<I>(indices);
793 rtn *= axis.width(idx);
794 }
795 };
796 MetaUtils::staticFor<Binning::Dimension::value>(getCAxisWidths);
797
798 return rtn;
799 }
800
801}
802
803#endif
size_t countOverflowBins(const size_t axisN) const noexcept
Count number of overflow bins.
Definition Binning.h:485
size_t globalIndexAt(const EdgeTypesTuple &coords) const
calculates global index for a given array of input values
Definition Binning.h:446
bool isMasked(const size_t i) const noexcept
Check if bin is masked.
Definition Binning.h:547
void updateMaskedBins() noexcept
Helper function to extract and mask index slices corresponding to masked bins along the axes.
Definition Binning.h:209
void clearMaskedBins() noexcept
Clear masked bins.
Definition Binning.h:172
std::tuple_element_t< I, std::tuple< Axes... > > getAxisT
Definition Binning.h:71
void maskBin(const size_t index, const bool status=true)
Mask/Unmask bin with global index index.
Definition Binning.h:512
Binning(const Binning &other)
Copy constructor.
Definition Binning.h:122
typename std::is_arithmetic< getEdgeT< I > > is_Arithmetic
Definition Binning.h:80
Binning(std::initializer_list< typename Axes::EdgeT > &&... edges)
Constructs binning from Rvalue vectors of axes' edges.
Definition Binning.h:104
std::array< size_t, sizeof...(Axes)> IndexArr
Definition Binning.h:61
const getAxisT< I > & axis() const noexcept
Extracts axis corresponding to dimension. Const version.
Binning(Axes &&... axes)
Constructs binning from a sequence of Rvalue axes.
Definition Binning.h:116
void mergeBins(std::decay_t< decltype(AxisNs, std::declval< std::pair< size_t, size_t > >())>... mergeRanges) noexcept
Definition Binning.h:666
Binning()
Nullary constructor for unique pointers etc.
Definition Binning.h:95
std::enable_if_t< std::is_floating_point< E >::value, std::vector< E > > widths(const bool includeOverflows=false) const noexcept
Templated version to get bin widths of axis N by reference.
Definition Binning.h:307
IndexArr globalToLocalIndices(size_t globalIndex) const
calculates array of local indices from a global index
Definition Binning.h:408
void maskBinAt(const EdgeTypesTuple &coords, const bool status=true) noexcept
Mask/Unmask bin at set of @ coords.
Definition Binning.h:523
Binning(const Axes &... axes)
Constructs binning from a sequence of axes.
Definition Binning.h:110
decltype(std::tuple_cat(std::declval< std::tuple< typename Axes::EdgeT > >()...)) EdgeTypesTuple
Definition Binning.h:85
std::vector< size_t > sliceIndices(std::vector< std::pair< size_t, std::vector< size_t > > >) const noexcept
Calculates indices of bins located in the specified slices.
Definition Binning.h:574
typename std::is_floating_point< getEdgeT< I > > is_CAxis
Definition Binning.h:77
Binning & operator=(const Binning &other)
Copy assignment.
Definition Binning.h:128
std::vector< size_t > maskedBins() const noexcept
Calculates indices of masked bins.
Definition Binning.h:169
std::integral_constant< size_t, sizeof...(Axes)> Dimension
Definition Binning.h:87
size_t numBins(const bool includeOverflows=true, const bool includeMaskedBins=true) const noexcept
get total number of bins in Binning
Definition Binning.h:739
IndexArr localIndicesAt(const EdgeTypesTuple &coords) const
assembles array of local indices for an array of input values
Definition Binning.h:431
void maskSlice(const size_t dim, const size_t idx, const bool status=true)
Mask a slice of the binning at local bin index idx along axis dimesnion dim.
Definition Binning.h:539
Binning(Binning &&other)
Move constructor.
Definition Binning.h:125
Binning(const std::initializer_list< typename Axes::EdgeT > &... edges)
Constructs binning from vectors of axes' edges.
Definition Binning.h:98
typename std::conjunction< std::is_floating_point< typename Axes::EdgeT >... > all_CAxes
Definition Binning.h:82
size_t calcSliceSize(const size_t pivotAxisN) const noexcept
Calculates size of a binning slice.
Definition Binning.h:561
Binning & operator=(Binning &&other)
Move assignment.
Definition Binning.h:137
std::enable_if_t< std::is_floating_point< E >::value, E > max() const noexcept
Get the highest non-overflow edge of the axis.
Definition Binning.h:326
EdgeTypesTuple edgeTuple(const size_t index) const noexcept
Return a coordinate tuple for bin index.
Definition Binning.h:762
bool isVisible(const size_t i) const noexcept
Check if bin is in visible range.
Definition Binning.h:554
typename getAxisT< I >::EdgeT getEdgeT
Definition Binning.h:74
size_t localToGlobalIndex(const IndexArr &localIndices) const
calculates global index from array of local indices
Definition Binning.h:386
void maskBins(const std::vector< size_t > &indices, const bool status=true)
Mask/Unmask bins in list of global indices.
Definition Binning.h:529
size_t numBinsAt(const size_t axisN, const bool includeOverflows=true) const noexcept
get number of bins at axis
Definition Binning.h:754
bool isCompatible(const Binning< Axes... > &other) const noexcept
checks if Binnings are compatible
Definition Binning.h:717
size_t dim() const noexcept
get dimension of Binning
Definition Binning.h:711
std::vector< E > edges(const bool includeOverflows=false) const noexcept
Templated version to get edges of axis N by value.
Definition Binning.h:286
std::vector< size_t > calcOverflowBinsIndices() const noexcept
Calculates indices of overflow bins.
Definition Binning.h:451
double dVol(const size_t index) const
Return the differential volume for bin index.
Definition Binning.h:784
std::enable_if_t< std::is_floating_point< E >::value, E > min() const noexcept
Get the lowest non-overflow edge of the axis.
Definition Binning.h:316
Error for e.g. use of invalid bin ranges.
Definition Exceptions.h:34
constexpr void staticFor(Func &&f)
Used to apply functor on tuple. Calls lambda with integral constant, which can be used to query tuple...
Definition MetaUtils.h:34
Anonymous namespace to limit visibility.
bool containsNan(const std::tuple< Args... > &coords)
Checks if a coordinate tuple has a nan.
Definition Binning.h:30
double nullifyIfDiscCoord(CoordT &&, std::false_type, double null=0.0)
Nullifies coordinate if it is discrete.
Definition Binning.h:19