1313#define FRAMEWORK_BINNINGPOLICY_H
1414
1515#include " Framework/HistogramSpec.h" // only for VARIABLE_WIDTH
16- #include " Framework/ASoAHelpers.h"
1716#include " Framework/Pack.h"
1817#include " Framework/ArrowTypes.h"
1918#include < optional>
2019
2120namespace o2 ::framework
2221{
2322
24- template <typename C, typename ... Cs>
25- struct BinningPolicy {
26- BinningPolicy (std::array<std::vector<double >, sizeof ...(Cs) + 1 > bins, bool ignoreOverflows = true ) : mBins (bins), mIgnoreOverflows (ignoreOverflows)
23+ namespace binning_helpers
24+ {
25+ void expandConstantBinning (std::vector<double > const & bins, std::vector<double >& expanded)
26+ {
27+ if (bins[0 ] != VARIABLE_WIDTH ) {
28+ int nBins = static_cast <int >(bins[0 ]);
29+ expanded.clear ();
30+ expanded.resize (nBins + 2 );
31+ expanded[0 ] = VARIABLE_WIDTH ;
32+ for (int i = 0 ; i <= nBins; i++) {
33+ expanded[i + 1 ] = bins[1 ] + i * (bins[2 ] - bins[1 ]) / nBins;
34+ }
35+ }
36+ }
37+ } // namespace binning_helpers
38+
39+ template <std::size_t N>
40+ struct BinningPolicyBase {
41+ BinningPolicyBase (std::array<std::vector<double >, N> bins, bool ignoreOverflows = true ) : mBins (bins), mIgnoreOverflows (ignoreOverflows)
2742 {
28- static_assert (sizeof ...(Cs) < 3 , " No default binning for more than 3 columns, you need to implement a binning class yourself" );
29- for (int i = 0 ; i < sizeof ...(Cs) + 1 ; i++) {
30- expandConstantBinning (bins[i], i );
43+ static_assert (N <= 3 , " No default binning for more than 3 columns, you need to implement a binning class yourself" );
44+ for (int i = 0 ; i < N ; i++) {
45+ binning_helpers:: expandConstantBinning (bins[i], mBins [i] );
3146 }
3247 }
3348
34- int getBin (std::tuple<typename C::type, typename Cs::type...> const & data) const
49+ template <typename ... Ts>
50+ int getBin (std::tuple<Ts...> const & data) const
3551 {
52+ static_assert (sizeof ...(Ts) == N, " There must be the same number of binning axes and data values/columns" );
53+
3654 unsigned int i = 2 , j = 2 , k = 2 ;
3755 if (this ->mIgnoreOverflows ) {
3856 // underflow
39- if (std::get<0 >(data) < this ->mBins [0 ][1 ]) { // xBins [0] is a dummy VARIABLE_WIDTH
57+ if (std::get<0 >(data) < this ->mBins [0 ][1 ]) { // mBins[0] [0] is a dummy VARIABLE_WIDTH
4058 return -1 ;
4159 }
42- if constexpr (sizeof ...(Cs) > 0 ) {
43- if (std::get<1 >(data) < this ->mBins [1 ][1 ]) { // this-> mBins[1][0] is a dummy VARIABLE_WIDTH
60+ if constexpr (N > 1 ) {
61+ if (std::get<1 >(data) < this ->mBins [1 ][1 ]) { // mBins[1][0] is a dummy VARIABLE_WIDTH
4462 return -1 ;
4563 }
4664 }
47- if constexpr (sizeof ...(Cs) > 1 ) {
48- if (std::get<2 >(data) < this ->mBins [2 ][1 ]) { // this-> mBins[2][0] is a dummy VARIABLE_WIDTH
65+ if constexpr (N > 2 ) {
66+ if (std::get<2 >(data) < this ->mBins [2 ][1 ]) { // mBins[2][0] is a dummy VARIABLE_WIDTH
4967 return -1 ;
5068 }
5169 }
@@ -58,11 +76,11 @@ struct BinningPolicy {
5876 for (; i < this ->mBins [0 ].size (); i++) {
5977 if (std::get<0 >(data) < this ->mBins [0 ][i]) {
6078
61- if constexpr (sizeof ...(Cs) > 0 ) {
79+ if constexpr (N > 1 ) {
6280 for (; j < this ->mBins [1 ].size (); j++) {
6381 if (std::get<1 >(data) < this ->mBins [1 ][j]) {
6482
65- if constexpr (sizeof ...(Cs) > 1 ) {
83+ if constexpr (N > 2 ) {
6684 for (; k < this ->mBins [2 ].size (); k++) {
6785 if (std::get<2 >(data) < this ->mBins [2 ][k]) {
6886 return getBinAt (i, j, k);
@@ -73,7 +91,7 @@ struct BinningPolicy {
7391 }
7492 }
7593
76- // overflow for this-> mBins[2] only
94+ // overflow for mBins[2] only
7795 return getBinAt (i, j, k);
7896 }
7997 }
@@ -82,8 +100,8 @@ struct BinningPolicy {
82100 return -1 ;
83101 }
84102
85- // overflow for this-> mBins[1] only
86- if constexpr (sizeof ...(Cs) > 1 ) {
103+ // overflow for mBins[1] only
104+ if constexpr (N > 2 ) {
87105 for (k = 2 ; k < this ->mBins [2 ].size (); k++) {
88106 if (std::get<2 >(data) < this ->mBins [2 ][k]) {
89107 return getBinAt (i, j, k);
@@ -92,7 +110,7 @@ struct BinningPolicy {
92110 }
93111 }
94112
95- // overflow for this-> mBins[2] and this-> mBins[1]
113+ // overflow for mBins[2] and mBins[1]
96114 return getBinAt (i, j, k);
97115 }
98116 }
@@ -102,27 +120,27 @@ struct BinningPolicy {
102120 return -1 ;
103121 }
104122
105- // overflow for this-> mBins[0] only
106- if constexpr (sizeof ...(Cs) > 0 ) {
123+ // overflow for mBins[0] only
124+ if constexpr (N > 1 ) {
107125 for (j = 2 ; j < this ->mBins [1 ].size (); j++) {
108126 if (std::get<1 >(data) < this ->mBins [1 ][j]) {
109127
110- if constexpr (sizeof ...(Cs) > 1 ) {
128+ if constexpr (N > 2 ) {
111129 for (k = 2 ; k < this ->mBins [2 ].size (); k++) {
112130 if (std::get<2 >(data) < this ->mBins [2 ][k]) {
113131 return getBinAt (i, j, k);
114132 }
115133 }
116134 }
117135
118- // overflow for this-> mBins[0] and this-> mBins[2]
136+ // overflow for mBins[0] and mBins[2]
119137 return getBinAt (i, j, k);
120138 }
121139 }
122140 }
123141
124- // overflow for this-> mBins[0] and this-> mBins[1]
125- if constexpr (sizeof ...(Cs) > 1 ) {
142+ // overflow for mBins[0] and mBins[1]
143+ if constexpr (N > 2 ) {
126144 for (k = 2 ; k < this ->mBins [2 ].size (); k++) {
127145 if (std::get<2 >(data) < this ->mBins [2 ][k]) {
128146 return getBinAt (i, j, k);
@@ -137,43 +155,44 @@ struct BinningPolicy {
137155 // Note: Overflow / underflow bin -1 is not included
138156 int getXBinsCount () const
139157 {
140- return this -> mBins [0 ]. size () - 1 - getOverflowShift ( );
158+ return getBinsCount ( mBins [0 ]);
141159 }
142160
143161 // Note: Overflow / underflow bin -1 is not included
144162 int getYBinsCount () const
145163 {
146- if constexpr (sizeof ...(Cs) == 0 ) {
164+ if constexpr (N == 1 ) {
147165 return 0 ;
148166 }
149- return this -> mBins [1 ]. size () - 1 - getOverflowShift ( );
167+ return getBinsCount ( mBins [1 ]);
150168 }
151169
152170 // Note: Overflow / underflow bin -1 is not included
153171 int getZBinsCount () const
154172 {
155- if constexpr (sizeof ...(Cs) < 2 ) {
173+ if constexpr (N < 3 ) {
156174 return 0 ;
157175 }
158- return this -> mBins [2 ]. size () - 1 - getOverflowShift ( );
176+ return getBinsCount ( mBins [2 ]);
159177 }
160178
161179 // Note: Overflow / underflow bin -1 is not included
162180 int getAllBinsCount () const
163181 {
164- if constexpr (sizeof ...(Cs) == 0 ) {
182+ if constexpr (N == 1 ) {
165183 return getXBinsCount ();
166184 }
167- if constexpr (sizeof ...(Cs) == 1 ) {
185+ if constexpr (N == 2 ) {
168186 return getXBinsCount () * getYBinsCount ();
169187 }
170- if constexpr (sizeof ...(Cs) == 2 ) {
188+ if constexpr (N == 2 ) {
171189 return getXBinsCount () * getYBinsCount () * getZBinsCount ();
172190 }
173191 return -1 ;
174192 }
175193
176- using persistent_columns_t = framework::selected_pack<o2::soa::is_persistent_t , C, Cs...>;
194+ std::array<std::vector<double >, N> mBins ;
195+ bool mIgnoreOverflows ;
177196
178197 private:
179198 // We substract 1 to account for VARIABLE_WIDTH in the bins vector
@@ -186,12 +205,12 @@ struct BinningPolicy {
186205 unsigned int j = jRaw - 1 - shiftBinsWithoutOverflow;
187206 unsigned int k = kRaw - 1 - shiftBinsWithoutOverflow;
188207 auto xBinsCount = getXBinsCount ();
189- if constexpr (sizeof ...(Cs) == 0 ) {
208+ if constexpr (N == 1 ) {
190209 return i;
191- } else if constexpr (sizeof ...(Cs) == 1 ) {
210+ } else if constexpr (N == 2 ) {
192211 return i + j * xBinsCount;
193- } else if constexpr (sizeof ...(Cs) == 2 ) {
194- return i + j * xBinsCount + k * xBinsCount * ( this -> mBins [ 1 ]. size () - 1 - shiftBinsWithoutOverflow );
212+ } else if constexpr (N == 3 ) {
213+ return i + j * xBinsCount + k * xBinsCount * getYBinsCount ( );
195214 } else {
196215 return -1 ;
197216 }
@@ -202,28 +221,101 @@ struct BinningPolicy {
202221 return mIgnoreOverflows ? 1 : -1 ;
203222 }
204223
205- void expandConstantBinning (std::vector<double > const & bins, int ind)
224+ // Note: Overflow / underflow bin -1 is not included
225+ int getBinsCount (std::vector<double > const & bins) const
206226 {
207- if (bins[0 ] != VARIABLE_WIDTH ) {
208- int nBins = static_cast <int >(bins[0 ]);
209- this ->mBins [ind].clear ();
210- this ->mBins [ind].resize (nBins + 2 );
211- this ->mBins [ind][0 ] = VARIABLE_WIDTH ;
212- for (int i = 0 ; i <= nBins; i++) {
213- this ->mBins [ind][i + 1 ] = bins[1 ] + i * (bins[2 ] - bins[1 ]) / nBins;
227+ return bins.size () - 1 - getOverflowShift ();
228+ }
229+ };
230+
231+ template <typename , typename ...>
232+ struct FlexibleBinningPolicy ;
233+
234+ template <typename ... Ts, typename ... Ls>
235+ struct FlexibleBinningPolicy <std::tuple<Ls...>, Ts...> : BinningPolicyBase<sizeof ...(Ts)> {
236+ FlexibleBinningPolicy (std::tuple<Ls...> const & lambdaPtrs, std::array<std::vector<double >, sizeof ...(Ts)> bins, bool ignoreOverflows = true ) : BinningPolicyBase<sizeof ...(Ts)>(bins, ignoreOverflows), mBinningFunctions {lambdaPtrs}
237+ {
238+ }
239+
240+ template <typename T, typename T2 >
241+ auto getBinningValue (T& rowIterator, arrow::Table* table, uint64_t globalIndex = -1 , uint64_t ci = -1 , uint64_t ai = -1 ) const
242+ {
243+ using decayed = std::decay_t <T2 >;
244+ if (globalIndex == -1 ) {
245+ globalIndex = *(std::get<0 >(rowIterator.getIndices ()));
246+ }
247+
248+ if constexpr (has_type_v<T2 , pack<Ls...>>) {
249+ rowIterator.setCursor (globalIndex);
250+ return std::get<T2 >(mBinningFunctions )(rowIterator);
251+ } else {
252+ if (ci == -1 && ai == -1 ) {
253+ auto colIterator = static_cast <decayed>(rowIterator).mColumnIterator ;
254+ ci = colIterator.mCurrentChunk ;
255+ ai = *(colIterator.mCurrentPos ) - colIterator.mFirstIndex ;
214256 }
257+ return soa::row_helpers::getSingleRowData<T, T2 >(table, rowIterator, ci, ai, globalIndex);
215258 }
216259 }
217260
218- std::array<std::vector<double >, sizeof ...(Cs) + 1 > mBins ;
219- bool mIgnoreOverflows ;
261+ template <typename T>
262+ auto getBinningValues (T& rowIterator, arrow::Table* table, uint64_t globalIndex = -1 , uint64_t ci = -1 , uint64_t ai = -1 ) const
263+ {
264+ return std::make_tuple (getBinningValue<T, Ts>(rowIterator, table, globalIndex, ci, ai)...);
265+ }
266+
267+ template <typename T>
268+ auto getBinningValues (typename T::iterator rowIterator, T& table, uint64_t globalIndex = -1 , uint64_t ci = -1 , uint64_t ai = -1 ) const
269+ {
270+ return getBinningValues (rowIterator, table.asArrowTable ().get (), globalIndex, ci, ai);
271+ }
272+
273+ template <typename ... T2s>
274+ int getBin (std::tuple<T2s...> const & data) const
275+ {
276+ return BinningPolicyBase<sizeof ...(Ts)>::template getBin<T2s...>(data);
277+ }
278+
279+ using persistent_columns_t = framework::selected_pack<o2::soa::is_persistent_t , Ts...>;
280+
281+ private:
282+ std::tuple<Ls...> mBinningFunctions ;
220283};
221284
285+ template <typename ... Ts>
286+ struct ColumnBinningPolicy : BinningPolicyBase<sizeof ...(Ts)> {
287+ ColumnBinningPolicy (std::array<std::vector<double >, sizeof ...(Ts)> bins, bool ignoreOverflows = true ) : BinningPolicyBase<sizeof ...(Ts)>(bins, ignoreOverflows)
288+ {
289+ }
290+
291+ template <typename T>
292+ auto getBinningValues (T& rowIterator, arrow::Table* table, uint64_t ci, uint64_t ai, uint64_t globalIndex) const
293+ {
294+ return std::make_tuple (soa::row_helpers::getSingleRowData<T, Ts>(table, rowIterator, ci, ai, globalIndex)...);
295+ }
296+
297+ int getBin (std::tuple<typename Ts::type...> const & data) const
298+ {
299+ return BinningPolicyBase<sizeof ...(Ts)>::template getBin<typename Ts::type...>(data);
300+ }
301+
302+ using persistent_columns_t = framework::selected_pack<o2::soa::is_persistent_t , Ts...>;
303+ };
304+
305+ template <typename ... Ts>
306+ using BinningPolicy = ColumnBinningPolicy<Ts...>;
307+
222308template <typename C>
223309struct NoBinningPolicy {
224310 // Just take the bin number from the column data
225311 NoBinningPolicy () = default ;
226312
313+ template <typename T>
314+ auto getBinningValues (T& rowIterator, arrow::Table* table, uint64_t ci, uint64_t ai, uint64_t globalIndex) const
315+ {
316+ return std::make_tuple (soa::row_helpers::getSingleRowData<T, C>(table, rowIterator, ci, ai, globalIndex));
317+ }
318+
227319 int getBin (std::tuple<typename C::type> const & data) const
228320 {
229321 return std::get<0 >(data);
0 commit comments