File indexing completed on 2025-01-18 09:57:28
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #pragma once
0012
0013 #include <Gaudi/Accumulators.h>
0014 #include <Gaudi/MonitoringHub.h>
0015 #include <GaudiKernel/HistoDef.h>
0016
0017 #include <array>
0018 #include <cmath>
0019 #include <fmt/format.h>
0020 #include <nlohmann/json.hpp>
0021 #include <string>
0022 #include <type_traits>
0023 #include <utility>
0024 #include <vector>
0025
0026 namespace Gaudi::Accumulators {
0027
0028 namespace details {
0029 template <std::size_t, typename T>
0030 using alwaysT = T;
0031
0032 template <typename Type, unsigned int ND>
0033 struct GetTuple;
0034 template <typename Type, unsigned int ND>
0035 using GetTuple_t = typename GetTuple<Type, ND>::type;
0036 template <typename Type, unsigned int ND>
0037 struct GetTuple {
0038 using type =
0039 decltype( std::tuple_cat( std::declval<std::tuple<Type>>(), std::declval<GetTuple_t<Type, ND - 1>>() ) );
0040 };
0041 template <typename Type>
0042 struct GetTuple<Type, 1> {
0043 using type = std::tuple<Type>;
0044 };
0045
0046 inline void requireValidTitle( std::string_view sv ) {
0047 if ( !sv.empty() && ( std::isspace( sv.back() ) || std::isspace( sv.front() ) ) ) {
0048 throw GaudiException(
0049 fmt::format( "Histogram title \'{}\' has whitespace at front or back -- please remove", sv ),
0050 "Gaudi::Accumulators", StatusCode::FAILURE );
0051 }
0052 }
0053 }
0054
0055
0056
0057
0058 struct ExtractWeight {
0059 template <typename Arithmetic>
0060 constexpr decltype( auto ) operator()( const std::pair<Arithmetic, Arithmetic>& v ) const noexcept {
0061 return v.second;
0062 }
0063 };
0064
0065
0066
0067
0068 struct WeightedProduct {
0069 template <typename Arithmetic>
0070 constexpr decltype( auto ) operator()( const std::pair<Arithmetic, Arithmetic>& v ) const noexcept {
0071 return v.first * v.second;
0072 }
0073 };
0074
0075
0076
0077
0078 struct WeightedSquare {
0079 template <typename Arithmetic>
0080 constexpr decltype( auto ) operator()( const std::pair<Arithmetic, Arithmetic>& v ) const noexcept {
0081 return v.first * v.first * v.second;
0082 }
0083 };
0084
0085
0086
0087
0088
0089
0090
0091 template <atomicity Atomicity, typename Arithmetic>
0092 struct WeightedCountAccumulator
0093 : GenericAccumulator<std::pair<Arithmetic, Arithmetic>, Arithmetic, Atomicity, ExtractWeight> {
0094 using Base = GenericAccumulator<std::pair<Arithmetic, Arithmetic>, Arithmetic, Atomicity, ExtractWeight>;
0095 using Base::Base;
0096 using Base::operator+=;
0097
0098 WeightedCountAccumulator operator+=( const Arithmetic weight ) {
0099 *this += { Arithmetic{}, weight };
0100 return *this;
0101 }
0102 Arithmetic nEntries() const { return this->value(); }
0103 };
0104
0105
0106
0107
0108
0109
0110
0111 template <atomicity Atomicity, typename Arithmetic>
0112 struct WeightedSumAccumulator
0113 : GenericAccumulator<std::pair<Arithmetic, Arithmetic>, Arithmetic, Atomicity, WeightedProduct> {
0114 using GenericAccumulator<std::pair<Arithmetic, Arithmetic>, Arithmetic, Atomicity,
0115 WeightedProduct>::GenericAccumulator;
0116 Arithmetic sum() const { return this->value(); }
0117 };
0118
0119
0120
0121
0122
0123
0124 template <atomicity Atomicity, typename Arithmetic = double>
0125 struct WeightedSquareAccumulator
0126 : GenericAccumulator<std::pair<Arithmetic, Arithmetic>, Arithmetic, Atomicity, WeightedSquare> {
0127 using GenericAccumulator<std::pair<Arithmetic, Arithmetic>, Arithmetic, Atomicity,
0128 WeightedSquare>::GenericAccumulator;
0129 Arithmetic sum2() const { return this->value(); };
0130 };
0131
0132
0133
0134
0135
0136
0137 template <atomicity Atomicity, typename Arithmetic>
0138 using WeightedAveragingAccumulator =
0139 AveragingAccumulatorBase<Atomicity, Arithmetic, WeightedCountAccumulator, WeightedSumAccumulator>;
0140
0141
0142
0143
0144
0145
0146 template <atomicity Atomicity, typename Arithmetic>
0147 using WeightedSigmaAccumulator =
0148 SigmaAccumulatorBase<Atomicity, Arithmetic, WeightedAveragingAccumulator, WeightedSquareAccumulator>;
0149
0150
0151
0152
0153 template <typename Arithmetic>
0154 struct Axis {
0155 Axis( unsigned int _nBins, Arithmetic _minValue, Arithmetic _maxValue, std::string _title = {},
0156 std::vector<std::string> _labels = {} )
0157 : nBins( _nBins )
0158 , minValue( _minValue )
0159 , maxValue( _maxValue )
0160 , title( std::move( _title ) )
0161 , labels( std::move( _labels ) )
0162 , ratio( _nBins / ( _maxValue - _minValue ) ) {
0163 details::requireValidTitle( title );
0164 for ( const auto& s : labels ) details::requireValidTitle( s );
0165 };
0166 explicit Axis( Gaudi::Histo1DDef const& def )
0167 : Axis( (unsigned int)def.bins(), def.lowEdge(), def.highEdge(), def.title() ){};
0168
0169 unsigned int nBins;
0170
0171 Arithmetic minValue, maxValue;
0172
0173 std::string title;
0174
0175 std::vector<std::string> labels;
0176
0177
0178
0179
0180 Arithmetic ratio;
0181
0182
0183 unsigned int index( Arithmetic value ) const {
0184
0185
0186 int idx;
0187 if constexpr ( std::is_integral_v<Arithmetic> ) {
0188 idx = ( ( value - minValue ) * nBins / ( maxValue - minValue ) ) + 1;
0189 } else {
0190 idx = std::floor( ( value - minValue ) * ratio ) + 1;
0191 }
0192 return idx < 0 ? 0 : ( (unsigned int)idx > nBins ? nBins + 1 : (unsigned int)idx );
0193 }
0194
0195 bool inAcceptance( Arithmetic value ) const { return value >= minValue && value <= maxValue; }
0196 };
0197
0198
0199 template <typename Arithmetic>
0200 void to_json( nlohmann::json& j, const Axis<Arithmetic>& axis ) {
0201 j = nlohmann::json{ { "nBins", axis.nBins },
0202 { "minValue", axis.minValue },
0203 { "maxValue", axis.maxValue },
0204 { "title", axis.title } };
0205 if ( !axis.labels.empty() ) { j["labels"] = axis.labels; }
0206 }
0207
0208
0209 template <typename Arithmetic, unsigned int ND, unsigned int NIndex = ND>
0210 struct HistoInputType : std::array<Arithmetic, ND> {
0211
0212 template <class... ARGS, typename = typename std::enable_if_t<( sizeof...( ARGS ) == NIndex )>>
0213 HistoInputType( ARGS... args ) : std::array<Arithmetic, ND>{ static_cast<Arithmetic>( args )... } {}
0214
0215 using ValueType = HistoInputType<Arithmetic, NIndex == 1 ? 1 : ND, NIndex>;
0216 using AxisArithmeticType = Arithmetic;
0217 using InternalType = std::array<Arithmetic, ND>;
0218 unsigned int computeIndex( const std::array<Axis<Arithmetic>, NIndex>& axis ) const {
0219 unsigned int index = 0;
0220 for ( unsigned int j = 0; j < NIndex; j++ ) {
0221 unsigned int dim = NIndex - j - 1;
0222
0223 int localIndex = axis[dim].index( ( *this )[dim] );
0224
0225 index *= ( axis[dim].nBins + 2 );
0226 index += localIndex;
0227 }
0228 return index;
0229 }
0230 bool inAcceptance( const std::array<Axis<Arithmetic>, NIndex>& axis ) const {
0231 for ( unsigned int dim = 0; dim < NIndex; dim++ ) {
0232 if ( !axis[dim].inAcceptance( ( *this )[dim] ) ) return false;
0233 }
0234 return true;
0235 }
0236 auto forInternalCounter() { return 1ul; }
0237 template <typename AxisType, long unsigned NAxis>
0238 static unsigned int computeTotNBins( std::array<AxisType, NAxis> axis ) {
0239 unsigned int nTotBins = 1;
0240 for ( unsigned int i = 0; i < NAxis; i++ ) { nTotBins *= ( axis[i].nBins + 2 ); }
0241 return nTotBins;
0242 }
0243 };
0244
0245
0246
0247 template <typename Arithmetic>
0248 class HistoInputType<Arithmetic, 1> {
0249 public:
0250 using ValueType = HistoInputType;
0251 using AxisArithmeticType = Arithmetic;
0252 using InternalType = Arithmetic;
0253 HistoInputType( Arithmetic a ) : value( a ) {}
0254 unsigned int computeIndex( const std::array<Axis<Arithmetic>, 1>& axis ) const { return axis[0].index( value ); }
0255 bool inAcceptance( const std::array<Axis<Arithmetic>, 1>& axis ) const { return axis[0].inAcceptance( value ); }
0256 Arithmetic& operator[]( int ) { return value; }
0257 operator Arithmetic() const { return value; }
0258 auto forInternalCounter() { return 1ul; }
0259 template <typename AxisType>
0260 static unsigned int computeTotNBins( std::array<AxisType, 1> axis ) {
0261 return axis[0].nBins + 2;
0262 }
0263
0264 private:
0265 Arithmetic value;
0266 };
0267
0268
0269 template <typename Arithmetic, unsigned int ND, unsigned int NIndex = ND>
0270 struct WeightedHistoInputType : std::pair<HistoInputType<Arithmetic, ND, NIndex>, Arithmetic> {
0271
0272 using ValueType = HistoInputType<Arithmetic, NIndex == 1 ? 1 : ND, NIndex>;
0273 using AxisArithmeticType = Arithmetic;
0274 using std::pair<HistoInputType<Arithmetic, ND, NIndex>, Arithmetic>::pair;
0275 unsigned int computeIndex( const std::array<Axis<Arithmetic>, NIndex>& axis ) const {
0276 return this->first.computeIndex( axis );
0277 }
0278 unsigned int inAcceptance( const std::array<Axis<Arithmetic>, NIndex>& axis ) const {
0279 return this->first.inAcceptance( axis );
0280 }
0281 auto forInternalCounter() { return std::pair( this->first.forInternalCounter(), this->second ); }
0282 template <typename AxisType, long unsigned NAxis>
0283 static unsigned int computeTotNBins( std::array<AxisType, NAxis> axis ) {
0284 return HistoInputType<Arithmetic, ND, NIndex>::computeTotNBins( axis );
0285 }
0286 };
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302 template <atomicity Atomicity, typename InputType, typename Arithmetic, typename ND,
0303 template <atomicity Ato, typename Arith> typename BaseAccumulatorT>
0304 class HistogramingAccumulatorInternal {
0305 template <atomicity, typename, typename, typename, template <atomicity, typename> typename>
0306 friend class HistogramingAccumulatorInternal;
0307
0308 public:
0309 using BaseAccumulator = BaseAccumulatorT<Atomicity, Arithmetic>;
0310 using AxisArithmeticType = typename InputType::AxisArithmeticType;
0311 using AxisType = Axis<AxisArithmeticType>;
0312 template <std::size_t... Is>
0313 HistogramingAccumulatorInternal( details::GetTuple_t<AxisType, ND::value> axis, std::index_sequence<Is...> )
0314 : m_axis{ std::get<Is>( axis )... }
0315 , m_totNBins{ InputType::computeTotNBins( m_axis ) }
0316 , m_value( new BaseAccumulator[m_totNBins] ) {
0317 reset();
0318 }
0319 template <atomicity ato>
0320 HistogramingAccumulatorInternal(
0321 construct_empty_t,
0322 const HistogramingAccumulatorInternal<ato, InputType, Arithmetic, ND, BaseAccumulatorT>& other )
0323 : m_axis( other.m_axis )
0324 , m_totNBins{ InputType::computeTotNBins( m_axis ) }
0325 , m_value( new BaseAccumulator[m_totNBins] ) {
0326 reset();
0327 }
0328 [[deprecated( "Use `++h1[x]`, `++h2[{x,y}]`, etc. instead." )]] HistogramingAccumulatorInternal&
0329 operator+=( InputType v ) {
0330 accumulator( v.computeIndex( m_axis ) ) += v.forInternalCounter();
0331 return *this;
0332 }
0333 void reset() {
0334 for ( unsigned int index = 0; index < m_totNBins; index++ ) accumulator( index ).reset();
0335 }
0336 template <atomicity ato>
0337 void mergeAndReset( HistogramingAccumulatorInternal<ato, InputType, Arithmetic, ND, BaseAccumulatorT>& other ) {
0338 assert( m_totNBins == other.m_totNBins );
0339 for ( unsigned int index = 0; index < m_totNBins; index++ ) {
0340 accumulator( index ).mergeAndReset( other.accumulator( index ) );
0341 }
0342 }
0343 [[nodiscard]] auto operator[]( typename InputType::ValueType v ) {
0344 return Buffer<BaseAccumulatorT, Atomicity, Arithmetic>{ accumulator( v.computeIndex( m_axis ) ) };
0345 }
0346
0347 auto& axis() const { return m_axis; }
0348 auto nBins( unsigned int i ) const { return m_axis[i].nBins; }
0349 auto minValue( unsigned int i ) const { return m_axis[i].minValue; }
0350 auto maxValue( unsigned int i ) const { return m_axis[i].maxValue; }
0351 auto binValue( unsigned int i ) const { return accumulator( i ).value(); }
0352 auto nEntries( unsigned int i ) const { return accumulator( i ).nEntries(); }
0353 auto totNBins() const { return m_totNBins; }
0354
0355 private:
0356 BaseAccumulator& accumulator( unsigned int index ) const {
0357 assert( index < m_totNBins );
0358 return m_value[index];
0359 }
0360
0361 std::array<AxisType, ND::value> m_axis;
0362
0363 unsigned int m_totNBins;
0364
0365 std::unique_ptr<BaseAccumulator[]> m_value;
0366 };
0367
0368
0369
0370
0371
0372
0373 template <atomicity Atomicity, typename Arithmetic, typename ND>
0374 using HistogramingAccumulator = HistogramingAccumulatorInternal<Atomicity, HistoInputType<Arithmetic, ND::value>,
0375 unsigned long, ND, IntegralAccumulator>;
0376
0377
0378
0379
0380
0381
0382 template <atomicity Atomicity, typename Arithmetic, typename ND>
0383 using WeightedHistogramingAccumulator =
0384 HistogramingAccumulatorInternal<Atomicity, WeightedHistoInputType<Arithmetic, ND::value>, Arithmetic, ND,
0385 WeightedCountAccumulator>;
0386
0387
0388
0389
0390
0391
0392 template <atomicity Atomicity, typename Arithmetic, typename ND>
0393 using ProfileHistogramingAccumulator =
0394 HistogramingAccumulatorInternal<Atomicity, HistoInputType<Arithmetic, ND::value + 1, ND::value>, Arithmetic, ND,
0395 SigmaAccumulator>;
0396
0397
0398
0399
0400
0401
0402 template <atomicity Atomicity, typename Arithmetic, typename ND>
0403 using WeightedProfileHistogramingAccumulator =
0404 HistogramingAccumulatorInternal<Atomicity, WeightedHistoInputType<Arithmetic, ND::value + 1, ND::value>,
0405 Arithmetic, ND, WeightedSigmaAccumulator>;
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456
0457
0458
0459
0460
0461
0462 template <unsigned int ND, atomicity Atomicity, typename Arithmetic, const char* Type,
0463 template <atomicity, typename, typename> typename Accumulator, typename Seq>
0464 class HistogramingCounterBaseInternal;
0465 template <unsigned int ND, atomicity Atomicity, typename Arithmetic, const char* Type,
0466 template <atomicity, typename, typename> typename Accumulator, std::size_t... NDs>
0467 class HistogramingCounterBaseInternal<ND, Atomicity, Arithmetic, Type, Accumulator, std::index_sequence<NDs...>>
0468 : public BufferableCounter<Atomicity, Accumulator, Arithmetic, std::integral_constant<int, ND>> {
0469 public:
0470 using Parent = BufferableCounter<Atomicity, Accumulator, Arithmetic, std::integral_constant<int, ND>>;
0471 using AccumulatorType = Accumulator<Atomicity, Arithmetic, std::integral_constant<int, ND>>;
0472 using NumberDimensions = std::integral_constant<unsigned int, ND>;
0473 inline static const std::string typeString{ std::string{ Type } + ':' + typeid( Arithmetic ).name() };
0474 template <typename OWNER>
0475 HistogramingCounterBaseInternal( OWNER* owner, std::string const& name, std::string const& title,
0476 details::GetTuple_t<typename AccumulatorType::AxisType, ND> axis )
0477 : Parent( owner, name, *this, axis, std::make_index_sequence<ND>{} ), m_title( title ) {
0478 details::requireValidTitle( m_title );
0479 }
0480 template <typename OWNER>
0481 HistogramingCounterBaseInternal( OWNER* owner, std::string const& name, std::string const& title,
0482 details::alwaysT<NDs, typename AccumulatorType::AxisType>... allAxis )
0483 : HistogramingCounterBaseInternal( owner, name, title, std::make_tuple( allAxis... ) ) {}
0484 using Parent::print;
0485 template <typename stream>
0486 stream& printImpl( stream& o, bool ) const {
0487 o << ND << "D Histogram with config ";
0488 for ( unsigned int i = 0; i < ND; i++ ) {
0489 o << this->nBins( i ) << " " << this->minValue( i ) << " " << this->maxValue( i ) << " ";
0490 }
0491 return o;
0492 }
0493 std::ostream& print( std::ostream& o, bool tableFormat = false ) const override {
0494 return printImpl( o, tableFormat );
0495 }
0496 MsgStream& print( MsgStream& o, bool tableFormat = false ) const override { return printImpl( o, tableFormat ); }
0497 friend void reset( HistogramingCounterBaseInternal& c ) { c.reset(); }
0498 friend void mergeAndReset( HistogramingCounterBaseInternal& h, HistogramingCounterBaseInternal& o ) {
0499 h.mergeAndReset( o );
0500 }
0501 friend void to_json( nlohmann::json& j, HistogramingCounterBaseInternal const& h ) {
0502
0503 std::vector<typename AccumulatorType::BaseAccumulator::OutputType> bins;
0504 bins.reserve( h.totNBins() );
0505 unsigned long totNEntries{ 0 };
0506 for ( unsigned int i = 0; i < h.totNBins(); i++ ) {
0507 bins.push_back( h.binValue( i ) );
0508 totNEntries += h.nEntries( i );
0509 }
0510
0511 j = { { "type", std::string( Type ) + ":" + typeid( Arithmetic ).name() },
0512 { "title", h.m_title },
0513 { "dimension", ND },
0514 { "empty", totNEntries == 0 },
0515 { "nEntries", totNEntries },
0516 { "axis", h.axis() },
0517 { "bins", bins } };
0518 }
0519
0520 private:
0521 std::string const m_title;
0522 };
0523 template <unsigned int ND, atomicity Atomicity, typename Arithmetic, const char* Type,
0524 template <atomicity, typename, typename> typename Accumulator>
0525 using HistogramingCounterBase =
0526 HistogramingCounterBaseInternal<ND, Atomicity, Arithmetic, Type, Accumulator, std::make_index_sequence<ND>>;
0527
0528 namespace naming {
0529 inline constexpr char histogramString[] = "histogram:Histogram";
0530 inline constexpr char weightedHistogramString[] = "histogram:WeightedHistogram";
0531 inline constexpr char profilehistogramString[] = "histogram:ProfileHistogram";
0532 inline constexpr char weightedProfilehistogramString[] = "histogram:WeightedProfileHistogram";
0533 }
0534
0535 template <unsigned int ND, atomicity Atomicity = atomicity::full, typename Arithmetic = double>
0536 using Histogram =
0537 HistogramingCounterBase<ND, Atomicity, Arithmetic, naming::histogramString, HistogramingAccumulator>;
0538
0539
0540 template <unsigned int ND, atomicity Atomicity = atomicity::full, typename Arithmetic = double>
0541 using WeightedHistogram = HistogramingCounterBase<ND, Atomicity, Arithmetic, naming::weightedHistogramString,
0542 WeightedHistogramingAccumulator>;
0543
0544
0545 template <unsigned int ND, atomicity Atomicity = atomicity::full, typename Arithmetic = double>
0546 using ProfileHistogram = HistogramingCounterBase<ND, Atomicity, Arithmetic, naming::profilehistogramString,
0547 ProfileHistogramingAccumulator>;
0548
0549
0550 template <unsigned int ND, atomicity Atomicity = atomicity::full, typename Arithmetic = double>
0551 using WeightedProfileHistogram =
0552 HistogramingCounterBase<ND, Atomicity, Arithmetic, naming::weightedProfilehistogramString,
0553 WeightedProfileHistogramingAccumulator>;
0554
0555 }