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/Histogram.h>
0014
0015 #include <type_traits>
0016
0017 namespace Gaudi::Accumulators {
0018
0019
0020
0021 constexpr unsigned int NSUMS( unsigned int ND ) { return 1 + ND + ND * ( ND + 1 ) / 2; }
0022
0023 template <typename Arithmetic, atomicity Atomicity, unsigned int ND>
0024 struct SigmasValueHandler {
0025 using InputType = std::conditional_t<ND == 1, Arithmetic, std::array<Arithmetic, ND>>;
0026 using OutputType = std::array<Arithmetic, NSUMS( ND )>;
0027 struct OutputTypeTS : std::array<std::atomic<Arithmetic>, NSUMS( ND )> {
0028
0029 using std::array<std::atomic<Arithmetic>, NSUMS( ND )>::array;
0030 explicit OutputTypeTS( OutputType const& other ) {
0031 for ( unsigned int i = 0; i < NSUMS( ND ); i++ ) { ( *this )[i] = other[i]; }
0032 }
0033
0034 OutputTypeTS& operator=( OutputType const& other ) {
0035 for ( unsigned int i = 0; i < NSUMS( ND ); i++ ) { ( *this )[i] = other[i]; }
0036 return *this;
0037 }
0038
0039 operator OutputType() const {
0040 OutputType out;
0041 for ( unsigned int i = 0; i < NSUMS( ND ); i++ ) { out[i] = ( *this )[i].load( std::memory_order_relaxed ); }
0042 return out;
0043 }
0044 };
0045 using InternalType = std::conditional_t<Atomicity == atomicity::full, OutputTypeTS, OutputType>;
0046 static constexpr OutputType getValue( const InternalType& v ) noexcept {
0047
0048 return v;
0049 };
0050 static OutputType exchange( InternalType& v, OutputType newv ) noexcept {
0051 if constexpr ( Atomicity == atomicity::full ) {
0052 OutputType old;
0053 for ( unsigned int i = 0; i < NSUMS( ND ); i++ ) { old[i] = v[i].exchange( newv[i] ); }
0054 return old;
0055 } else {
0056 return std::exchange( v, newv );
0057 }
0058 }
0059 static constexpr OutputType DefaultValue() { return InternalType{}; }
0060 static void merge( InternalType& a, OutputType b ) noexcept {
0061 if constexpr ( Atomicity == atomicity::full ) {
0062 for ( unsigned int i = 0; i < NSUMS( ND ); i++ ) { fetch_add( a[i], b[i] ); }
0063 } else {
0064 for ( unsigned int i = 0; i < ND * ( ND + 3 ); i++ ) a[i] += b[i];
0065 }
0066 }
0067 static void merge( InternalType& a, InputType b ) noexcept {
0068
0069 OutputType diff{};
0070 diff[0] = 1.;
0071 if constexpr ( ND == 1 ) {
0072
0073 diff[1] = b;
0074 diff[2] = b * b;
0075 } else {
0076 for ( unsigned int i = 0; i < ND; i++ ) diff[i + 1] += b[i];
0077 unsigned int n = 1 + ND;
0078 for ( unsigned int i = 0; i < ND; i++ ) {
0079 for ( unsigned int j = i; j < ND; j++ ) {
0080 diff[n] = b[i] * b[j];
0081 n++;
0082 }
0083 }
0084 }
0085
0086 if constexpr ( Atomicity == atomicity::full ) {
0087 for ( unsigned int i = 0; i < NSUMS( ND ); i++ ) { fetch_add( a[i], diff[i] ); }
0088 } else {
0089 for ( unsigned int i = 0; i < NSUMS( ND ); i++ ) a[i] += diff[i];
0090 }
0091 }
0092 };
0093
0094 template <typename Arithmetic, atomicity Atomicity, unsigned int ND>
0095 struct SigmaNAccumulator
0096 : GenericAccumulator<std::array<Arithmetic, ND>, std::array<Arithmetic, NSUMS( ND )>, Atomicity, Identity,
0097 Identity, SigmasValueHandler<Arithmetic, Atomicity, ND>> {
0098 std::array<Arithmetic, NSUMS( ND )> const sums() const { return this->value(); }
0099 };
0100
0101
0102 template <typename Arithmetic, atomicity Atomicity>
0103 struct SigmaNAccumulator<Arithmetic, Atomicity, 1>
0104 : GenericAccumulator<Arithmetic, std::array<Arithmetic, 3>, Atomicity, Identity, Identity,
0105 SigmasValueHandler<Arithmetic, Atomicity, 1>> {
0106 std::array<Arithmetic, 3> const sums() const { return this->value(); }
0107 };
0108
0109
0110
0111
0112
0113
0114 template <atomicity Atomicity, typename Arithmetic, unsigned int ND>
0115 class RootHistogramingAccumulatorInternal
0116 : public HistogramingAccumulatorInternal<Atomicity, HistoInputType<Arithmetic, ND>, unsigned long,
0117 std::integral_constant<int, ND>, IntegralAccumulator> {
0118
0119 using InputType = HistoInputType<Arithmetic, ND>;
0120 using Parent = HistogramingAccumulatorInternal<Atomicity, InputType, unsigned long, std::integral_constant<int, ND>,
0121 IntegralAccumulator>;
0122
0123 template <atomicity, typename, unsigned int>
0124 friend class RootHistogramingAccumulatorInternal;
0125
0126 static_assert( ND <= 3, "Root on supports histogrmas with dimension <= 3" );
0127
0128
0129
0130
0131
0132 struct Proxy {
0133 Proxy( RootHistogramingAccumulatorInternal& histo, typename InputType::ValueType& v )
0134 : m_histo( histo ), m_v( v ) {}
0135 void operator++() { m_histo.update( m_v ); }
0136 RootHistogramingAccumulatorInternal& m_histo;
0137 typename InputType::ValueType m_v;
0138 };
0139
0140 public:
0141 using Parent::Parent;
0142 friend struct Proxy;
0143
0144 [[deprecated( "Use `++h1[x]`, `++h2[{x,y}]`, etc. instead." )]] RootHistogramingAccumulatorInternal&
0145 operator+=( InputType v ) {
0146 update( v );
0147 return *this;
0148 }
0149 void reset() {
0150 m_accumulator.reset();
0151 Parent::reset();
0152 }
0153 template <atomicity ato>
0154 void mergeAndReset( RootHistogramingAccumulatorInternal<ato, Arithmetic, ND>& other ) {
0155 m_accumulator.mergeAndReset( other.m_accumulator );
0156 Parent::mergeAndReset( other );
0157 }
0158 [[nodiscard]] auto operator[]( typename InputType::ValueType v ) { return Proxy( *this, v ); }
0159
0160
0161
0162
0163
0164 auto sums2() const { return m_accumulator.sums(); }
0165
0166 private:
0167 void update( typename InputType::ValueType v ) {
0168
0169
0170 if ( v.inAcceptance( this->axis() ) ) { m_accumulator += static_cast<typename InputType::InternalType>( v ); }
0171 ++Parent::operator[]( v );
0172 }
0173
0174
0175 SigmaNAccumulator<Arithmetic, Atomicity, ND> m_accumulator;
0176 };
0177
0178 namespace {
0179
0180 template <typename Arithmetic>
0181 Arithmetic stddev( Arithmetic n, Arithmetic s, Arithmetic s2 ) {
0182 using Gaudi::Accumulators::sqrt;
0183 using std::sqrt;
0184 auto v = ( n > 0 ) ? ( ( s2 - s * ( s / n ) ) / n ) : Arithmetic{};
0185 return ( Arithmetic{ 0 } > v ) ? Arithmetic{} : sqrt( v );
0186 }
0187 }
0188
0189
0190
0191
0192 template <atomicity Atomicity, typename Arithmetic, typename ND>
0193 struct RootHistogramingAccumulator;
0194
0195 template <atomicity Atomicity, typename Arithmetic>
0196 struct RootHistogramingAccumulator<Atomicity, Arithmetic, std::integral_constant<int, 1>>
0197 : RootHistogramingAccumulatorInternal<Atomicity, Arithmetic, 1> {
0198 using RootHistogramingAccumulatorInternal<Atomicity, Arithmetic, 1>::RootHistogramingAccumulatorInternal;
0199 using RootHistogramingAccumulatorInternal<Atomicity, Arithmetic, 1>::nEntries;
0200 Arithmetic nEntries() const { return this->sums2()[0]; }
0201 Arithmetic sum() const { return this->sums2()[1]; }
0202 Arithmetic sum2() const { return this->sums2()[2]; }
0203 Arithmetic mean() const { return sum() / nEntries(); }
0204 Arithmetic standard_deviation() const { return stddev( nEntries(), sum(), sum2() ); }
0205 };
0206
0207 template <atomicity Atomicity, typename Arithmetic>
0208 struct RootHistogramingAccumulator<Atomicity, Arithmetic, std::integral_constant<int, 2>>
0209 : RootHistogramingAccumulatorInternal<Atomicity, Arithmetic, 2> {
0210 using RootHistogramingAccumulatorInternal<Atomicity, Arithmetic, 2>::RootHistogramingAccumulatorInternal;
0211 using RootHistogramingAccumulatorInternal<Atomicity, Arithmetic, 2>::nEntries;
0212 Arithmetic nEntries() const { return this->sums2()[0]; }
0213 Arithmetic sumx() const { return this->sums2()[1]; }
0214 Arithmetic sumy() const { return this->sums2()[2]; }
0215 Arithmetic sumx2() const { return this->sums2()[3]; }
0216 Arithmetic sumy2() const { return this->sums2()[5]; }
0217 Arithmetic sumxy() const { return this->sums2()[4]; }
0218 Arithmetic meanx() const { return sumx() / nEntries(); }
0219 Arithmetic meany() const { return sumy() / nEntries(); }
0220 Arithmetic standard_deviationx() const { return stddev( nEntries(), sumx(), sumx2() ); }
0221 Arithmetic standard_deviationy() const { return stddev( nEntries(), sumy(), sumy2() ); }
0222 };
0223
0224 template <atomicity Atomicity, typename Arithmetic>
0225 struct RootHistogramingAccumulator<Atomicity, Arithmetic, std::integral_constant<int, 3>>
0226 : RootHistogramingAccumulatorInternal<Atomicity, Arithmetic, 3> {
0227 using RootHistogramingAccumulatorInternal<Atomicity, Arithmetic, 3>::RootHistogramingAccumulatorInternal;
0228 using RootHistogramingAccumulatorInternal<Atomicity, Arithmetic, 3>::nEntries;
0229 Arithmetic nEntries() const { return this->sums2()[0]; }
0230 Arithmetic sumx() const { return this->sums2()[1]; }
0231 Arithmetic sumy() const { return this->sums2()[2]; }
0232 Arithmetic sumz() const { return this->sums2()[3]; }
0233 Arithmetic sumx2() const { return this->sums2()[4]; }
0234 Arithmetic sumy2() const { return this->sums2()[7]; }
0235 Arithmetic sumz2() const { return this->sums2()[9]; }
0236 Arithmetic sumxy() const { return this->sums2()[5]; }
0237 Arithmetic sumxz() const { return this->sums2()[6]; }
0238 Arithmetic sumyz() const { return this->sums2()[8]; }
0239 Arithmetic meanx() const { return sumx() / nEntries(); }
0240 Arithmetic meany() const { return sumy() / nEntries(); }
0241 Arithmetic meanz() const { return sumz() / nEntries(); }
0242 Arithmetic standard_deviationx() const { return stddev( nEntries(), sumx(), sumx2() ); }
0243 Arithmetic standard_deviationy() const { return stddev( nEntries(), sumy(), sumy2() ); }
0244 Arithmetic standard_deviationz() const { return stddev( nEntries(), sumz(), sumz2() ); }
0245 };
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265 template <unsigned int ND, atomicity Atomicity, typename Arithmetic, const char* Type>
0266 class RootHistogramingCounterBase;
0267
0268 template <atomicity Atomicity, typename Arithmetic, const char* Type>
0269 class RootHistogramingCounterBase<1, Atomicity, Arithmetic, Type>
0270 : public HistogramingCounterBaseInternal<1, Atomicity, Arithmetic, Type, RootHistogramingAccumulator,
0271 std::make_index_sequence<1>> {
0272 public:
0273 using Parent = HistogramingCounterBaseInternal<1, Atomicity, Arithmetic, Type, RootHistogramingAccumulator,
0274 std::make_index_sequence<1>>;
0275 using Parent::Parent;
0276
0277 friend void to_json( nlohmann::json& j, RootHistogramingCounterBase<1, Atomicity, Arithmetic, Type> const& h ) {
0278 to_json( j, static_cast<Parent const&>( h ) );
0279 j["nTotEntries"] = h.nEntries();
0280 j["sum"] = h.sum();
0281 j["mean"] = h.mean();
0282 j["sum2"] = h.sum2();
0283 j["standard_deviation"] = h.standard_deviation();
0284 }
0285 };
0286
0287 template <atomicity Atomicity, typename Arithmetic, const char* Type>
0288 class RootHistogramingCounterBase<2, Atomicity, Arithmetic, Type>
0289 : public HistogramingCounterBaseInternal<2, Atomicity, Arithmetic, Type, RootHistogramingAccumulator,
0290 std::make_index_sequence<2>> {
0291 public:
0292 using Parent = HistogramingCounterBaseInternal<2, Atomicity, Arithmetic, Type, RootHistogramingAccumulator,
0293 std::make_index_sequence<2>>;
0294 using Parent::Parent;
0295
0296 friend void to_json( nlohmann::json& j, RootHistogramingCounterBase<2, Atomicity, Arithmetic, Type> const& h ) {
0297 to_json( j, static_cast<Parent const&>( h ) );
0298 j["nTotEntries"] = h.nEntries();
0299 j["sumx"] = h.sumx();
0300 j["sumy"] = h.sumy();
0301 j["meanx"] = h.meanx();
0302 j["meany"] = h.meany();
0303 j["sumx2"] = h.sumx2();
0304 j["sumy2"] = h.sumy2();
0305 j["sumxy"] = h.sumxy();
0306 j["standard_deviationx"] = h.standard_deviationx();
0307 j["standard_deviationy"] = h.standard_deviationy();
0308 }
0309 };
0310
0311 template <atomicity Atomicity, typename Arithmetic, const char* Type>
0312 class RootHistogramingCounterBase<3, Atomicity, Arithmetic, Type>
0313 : public HistogramingCounterBaseInternal<3, Atomicity, Arithmetic, Type, RootHistogramingAccumulator,
0314 std::make_index_sequence<3>> {
0315 public:
0316 using Parent = HistogramingCounterBaseInternal<3, Atomicity, Arithmetic, Type, RootHistogramingAccumulator,
0317 std::make_index_sequence<3>>;
0318 using Parent::Parent;
0319
0320 friend void to_json( nlohmann::json& j, RootHistogramingCounterBase<3, Atomicity, Arithmetic, Type> const& h ) {
0321 to_json( j, static_cast<Parent const&>( h ) );
0322 j["nTotEntries"] = h.nEntries();
0323 j["sumx"] = h.sumx();
0324 j["sumy"] = h.sumy();
0325 j["sumz"] = h.sumz();
0326 j["meanx"] = h.meanx();
0327 j["meany"] = h.meany();
0328 j["meanz"] = h.meanz();
0329 j["sumx2"] = h.sumx2();
0330 j["sumy2"] = h.sumy2();
0331 j["sumz2"] = h.sumz2();
0332 j["sumxy"] = h.sumxy();
0333 j["sumxz"] = h.sumxz();
0334 j["sumyz"] = h.sumyz();
0335 j["standard_deviationx"] = h.standard_deviationx();
0336 j["standard_deviationy"] = h.standard_deviationy();
0337 j["standard_deviationz"] = h.standard_deviationz();
0338 }
0339 };
0340
0341
0342 template <unsigned int ND, atomicity Atomicity = atomicity::full, typename Arithmetic = double>
0343 using RootHistogram = RootHistogramingCounterBase<ND, Atomicity, Arithmetic, naming::histogramString>;
0344
0345 }