The Gaudi Framework  master (181af51f)
Loading...
Searching...
No Matches
StaticRootHistogram.h
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 1998-2024 CERN for the benefit of the LHCb and ATLAS collaborations *
3* *
4* This software is distributed under the terms of the Apache version 2 licence, *
5* copied verbatim in the file "LICENSE". *
6* *
7* In applying this licence, CERN does not waive the privileges and immunities *
8* granted to it by virtue of its status as an Intergovernmental Organization *
9* or submit itself to any jurisdiction. *
10\***********************************************************************************/
11#pragma once
12
14
15#include <type_traits>
16
17namespace {
18 template <typename tuple_t>
19 constexpr auto get_array_from_tuple( tuple_t&& tuple ) {
20 constexpr auto get_array = []( auto&&... x ) { return std::array{ std::forward<decltype( x )>( x )... }; };
21 return std::apply( get_array, std::forward<tuple_t>( tuple ) );
22 }
23} // namespace
24
25namespace Gaudi::Accumulators {
26
29 constexpr unsigned int NSUMS( unsigned int ND ) { return 1 + ND + ND * ( ND + 1 ) / 2; }
30
31 template <typename Arithmetic, atomicity Atomicity, unsigned int ND>
33 using InputType = std::conditional_t<ND == 1, Arithmetic, std::array<Arithmetic, ND>>;
34 using OutputType = std::array<Arithmetic, NSUMS( ND )>;
35 struct OutputTypeTS : std::array<std::atomic<Arithmetic>, NSUMS( ND )> {
37 using std::array<std::atomic<Arithmetic>, NSUMS( ND )>::array;
38 explicit OutputTypeTS( OutputType const& other ) {
39 for ( unsigned int i = 0; i < NSUMS( ND ); i++ ) { ( *this )[i] = other[i]; }
40 }
41 // operator= from non thread safe type
43 for ( unsigned int i = 0; i < NSUMS( ND ); i++ ) { ( *this )[i] = other[i]; }
44 return *this;
45 }
46 // automatic conversion to non thread safe type
47 operator OutputType() const {
48 OutputType out;
49 for ( unsigned int i = 0; i < NSUMS( ND ); i++ ) { out[i] = ( *this )[i].load( std::memory_order_relaxed ); }
50 return out;
51 }
52 };
53 using InternalType = std::conditional_t<Atomicity == atomicity::full, OutputTypeTS, OutputType>;
54 static constexpr OutputType getValue( const InternalType& v ) noexcept {
55 // Note automatic conversion will happen
56 return v;
57 };
58 static OutputType exchange( InternalType& v, OutputType newv ) noexcept {
59 if constexpr ( Atomicity == atomicity::full ) {
60 OutputType old;
61 for ( unsigned int i = 0; i < NSUMS( ND ); i++ ) { old[i] = v[i].exchange( newv[i] ); }
62 return old;
63 } else {
64 return std::exchange( v, newv );
65 }
66 }
67 static constexpr OutputType DefaultValue() { return InternalType{}; }
68 static void merge( InternalType& a, const OutputType& b ) noexcept {
69 if constexpr ( Atomicity == atomicity::full ) {
70 for ( unsigned int i = 0; i < NSUMS( ND ); i++ ) { fetch_add( a[i], b[i] ); }
71 } else {
72 for ( unsigned int i = 0; i < ND * ( ND + 3 ); i++ ) a[i] += b[i];
73 }
74 }
75 static void merge( InternalType& a, InputType b ) noexcept {
76 // prepare values to increment internal values
77 OutputType diff{};
78 diff[0] = 1.;
79 if constexpr ( ND == 1 ) {
80 // no operator[] for b in this case
81 diff[1] = b;
82 diff[2] = b * b;
83 } else {
84 for ( unsigned int i = 0; i < ND; i++ ) diff[i + 1] += b[i];
85 unsigned int n = 1 + ND;
86 for ( unsigned int i = 0; i < ND; i++ ) {
87 for ( unsigned int j = i; j < ND; j++ ) {
88 diff[n] = b[i] * b[j];
89 n++;
90 }
91 }
92 }
93 // Now increase original counter
94 if constexpr ( Atomicity == atomicity::full ) {
95 for ( unsigned int i = 0; i < NSUMS( ND ); i++ ) { fetch_add( a[i], diff[i] ); }
96 } else {
97 for ( unsigned int i = 0; i < NSUMS( ND ); i++ ) a[i] += diff[i];
98 }
99 }
100 };
101
102 template <typename Arithmetic, atomicity Atomicity, unsigned int ND>
104 : GenericAccumulator<std::array<Arithmetic, ND>, std::array<Arithmetic, NSUMS( ND )>, Atomicity, Identity,
105 Identity, SigmasValueHandler<Arithmetic, Atomicity, ND>> {
106 std::array<Arithmetic, NSUMS( ND )> const sums() const { return this->value(); }
107 };
108
110 template <typename Arithmetic, atomicity Atomicity>
111 struct SigmaNAccumulator<Arithmetic, Atomicity, 1>
112 : GenericAccumulator<Arithmetic, std::array<Arithmetic, 3>, Atomicity, Identity, Identity,
113 SigmasValueHandler<Arithmetic, Atomicity, 1>> {
114 std::array<Arithmetic, 3> const sums() const { return this->value(); }
115 };
116
122 template <atomicity Atomicity, typename Arithmetic, unsigned int ND, typename AxisTupleType>
124 : public HistogramingAccumulatorInternal<Atomicity, HistoInputType<AxisToArithmetic_t<AxisTupleType>, ND>,
125 unsigned long, IntegralAccumulator, AxisTupleType> {
126
128 using Parent =
130
131 template <atomicity, typename, unsigned int, typename>
133
134 static_assert( ND <= 3, "Root on supports histogrmas with dimension <= 3" );
135
140 struct Proxy {
141 Proxy( RootHistogramingAccumulatorInternal& histo, typename InputType::ValueType& v )
142 : m_histo( histo ), m_v( v ) {}
143 void operator++() { m_histo.update( m_v ); }
145 typename InputType::ValueType m_v;
146 };
147
148 public:
149 using Parent::Parent;
150 friend struct Proxy;
151
152 [[deprecated( "Use `++h1[x]`, `++h2[{x,y}]`, etc. instead." )]] RootHistogramingAccumulatorInternal&
153 operator+=( typename InputType::ValueType v ) {
154 update( v );
155 return *this;
156 }
157 void reset() {
158 m_accumulator.reset();
160 }
161 template <atomicity ato>
166 [[nodiscard]] auto operator[]( typename InputType::ValueType v ) { return Proxy( *this, v ); }
167
172 auto sums2() const { return m_accumulator.sums(); }
173
174 private:
175 void update( typename InputType::ValueType v ) {
176 // Do not accumulate in m_accumulator if we are outside the histo range
177 // We mimic here the behavior of ROOT
178 if ( v.inAcceptance( this->axis() ) ) {
179 if constexpr ( ND == 1 ) {
180 m_accumulator += std::get<0>( v );
181 } else {
182 m_accumulator += get_array_from_tuple( static_cast<typename InputType::InternalType>( v ) );
183 }
184 }
185 ++Parent::operator[]( v );
186 }
187 // Accumulator for keeping squared sum of value stored in the histogram and correlation values
188 // they get stored in "alphabetical" order, e.g. for ND=3 x^2, xy, xz, y^2, yz, z^2
190 };
191
192 namespace {
194 template <typename Arithmetic>
195 Arithmetic stddev( Arithmetic n, Arithmetic s, Arithmetic s2 ) {
197 using std::sqrt;
198 auto v = ( n > 0 ) ? ( ( s2 - s * ( s / n ) ) / n ) : Arithmetic{};
199 return ( Arithmetic{ 0 } > v ) ? Arithmetic{} : sqrt( v );
200 }
201 } // namespace
202
206 template <atomicity Atomicity, typename Arithmetic, typename ND, typename AxisTupleType>
208
209 template <atomicity Atomicity, typename Arithmetic, typename AxisTupleType>
210 struct RootHistogramingAccumulator<Atomicity, Arithmetic, std::integral_constant<unsigned int, 1>, AxisTupleType>
211 : RootHistogramingAccumulatorInternal<Atomicity, Arithmetic, 1, AxisTupleType> {
212 using RootHistogramingAccumulatorInternal<Atomicity, Arithmetic, 1,
214 using RootHistogramingAccumulatorInternal<Atomicity, Arithmetic, 1, AxisTupleType>::nEntries;
215 Arithmetic nEntries() const { return this->sums2()[0]; }
216 Arithmetic sum() const { return this->sums2()[1]; }
217 Arithmetic sum2() const { return this->sums2()[2]; }
218 Arithmetic mean() const { return sum() / nEntries(); }
219 Arithmetic standard_deviation() const { return stddev( nEntries(), sum(), sum2() ); }
220 };
221
222 template <atomicity Atomicity, typename Arithmetic, typename AxisTupleType>
223 struct RootHistogramingAccumulator<Atomicity, Arithmetic, std::integral_constant<unsigned int, 2>, AxisTupleType>
224 : RootHistogramingAccumulatorInternal<Atomicity, Arithmetic, 2, AxisTupleType> {
225 using RootHistogramingAccumulatorInternal<Atomicity, Arithmetic, 2,
227 using RootHistogramingAccumulatorInternal<Atomicity, Arithmetic, 2, AxisTupleType>::nEntries;
228 Arithmetic nEntries() const { return this->sums2()[0]; }
229 Arithmetic sumx() const { return this->sums2()[1]; }
230 Arithmetic sumy() const { return this->sums2()[2]; }
231 Arithmetic sumx2() const { return this->sums2()[3]; }
232 Arithmetic sumy2() const { return this->sums2()[5]; }
233 Arithmetic sumxy() const { return this->sums2()[4]; }
234 Arithmetic meanx() const { return sumx() / nEntries(); }
235 Arithmetic meany() const { return sumy() / nEntries(); }
236 Arithmetic standard_deviationx() const { return stddev( nEntries(), sumx(), sumx2() ); }
237 Arithmetic standard_deviationy() const { return stddev( nEntries(), sumy(), sumy2() ); }
238 };
239
240 template <atomicity Atomicity, typename Arithmetic, typename AxisTupleType>
241 struct RootHistogramingAccumulator<Atomicity, Arithmetic, std::integral_constant<unsigned int, 3>, AxisTupleType>
242 : RootHistogramingAccumulatorInternal<Atomicity, Arithmetic, 3, AxisTupleType> {
243 using RootHistogramingAccumulatorInternal<Atomicity, Arithmetic, 3,
245 using RootHistogramingAccumulatorInternal<Atomicity, Arithmetic, 3, AxisTupleType>::nEntries;
246 Arithmetic nEntries() const { return this->sums2()[0]; }
247 Arithmetic sumx() const { return this->sums2()[1]; }
248 Arithmetic sumy() const { return this->sums2()[2]; }
249 Arithmetic sumz() const { return this->sums2()[3]; }
250 Arithmetic sumx2() const { return this->sums2()[4]; }
251 Arithmetic sumy2() const { return this->sums2()[7]; }
252 Arithmetic sumz2() const { return this->sums2()[9]; }
253 Arithmetic sumxy() const { return this->sums2()[5]; }
254 Arithmetic sumxz() const { return this->sums2()[6]; }
255 Arithmetic sumyz() const { return this->sums2()[8]; }
256 Arithmetic meanx() const { return sumx() / nEntries(); }
257 Arithmetic meany() const { return sumy() / nEntries(); }
258 Arithmetic meanz() const { return sumz() / nEntries(); }
259 Arithmetic standard_deviationx() const { return stddev( nEntries(), sumx(), sumx2() ); }
260 Arithmetic standard_deviationy() const { return stddev( nEntries(), sumy(), sumy2() ); }
261 Arithmetic standard_deviationz() const { return stddev( nEntries(), sumz(), sumz2() ); }
262 };
263
282 template <unsigned int ND, atomicity Atomicity, typename Arithmetic, const char* Type, typename AxisTupleType>
284
285 template <atomicity Atomicity, typename Arithmetic, const char* Type, typename AxisTupleType>
286 class RootHistogramingCounterBase<1, Atomicity, Arithmetic, Type, AxisTupleType>
287 : public HistogramingCounterBase<1, Atomicity, Arithmetic, Type, RootHistogramingAccumulator, AxisTupleType> {
288 public:
290 using Parent::Parent;
291
292 friend void to_json( nlohmann::json& j,
294 to_json( j, static_cast<Parent const&>( h ) );
295 j["nTotEntries"] = h.nEntries();
296 j["sum"] = h.sum();
297 j["mean"] = h.mean();
298 j["sum2"] = h.sum2();
299 j["standard_deviation"] = h.standard_deviation();
300 }
301 };
302
303 template <atomicity Atomicity, typename Arithmetic, const char* Type, typename AxisTupleType>
304 class RootHistogramingCounterBase<2, Atomicity, Arithmetic, Type, AxisTupleType>
305 : public HistogramingCounterBase<2, Atomicity, Arithmetic, Type, RootHistogramingAccumulator, AxisTupleType> {
306 public:
308 using Parent::Parent;
309
310 friend void to_json( nlohmann::json& j,
312 to_json( j, static_cast<Parent const&>( h ) );
313 j["nTotEntries"] = h.nEntries();
314 j["sumx"] = h.sumx();
315 j["sumy"] = h.sumy();
316 j["meanx"] = h.meanx();
317 j["meany"] = h.meany();
318 j["sumx2"] = h.sumx2();
319 j["sumy2"] = h.sumy2();
320 j["sumxy"] = h.sumxy();
321 j["standard_deviationx"] = h.standard_deviationx();
322 j["standard_deviationy"] = h.standard_deviationy();
323 }
324 };
325
326 template <atomicity Atomicity, typename Arithmetic, const char* Type, typename AxisTupleType>
327 class RootHistogramingCounterBase<3, Atomicity, Arithmetic, Type, AxisTupleType>
328 : public HistogramingCounterBase<3, Atomicity, Arithmetic, Type, RootHistogramingAccumulator, AxisTupleType> {
329 public:
331 using Parent::Parent;
332
333 friend void to_json( nlohmann::json& j,
335 to_json( j, static_cast<Parent const&>( h ) );
336 j["nTotEntries"] = h.nEntries();
337 j["sumx"] = h.sumx();
338 j["sumy"] = h.sumy();
339 j["sumz"] = h.sumz();
340 j["meanx"] = h.meanx();
341 j["meany"] = h.meany();
342 j["meanz"] = h.meanz();
343 j["sumx2"] = h.sumx2();
344 j["sumy2"] = h.sumy2();
345 j["sumz2"] = h.sumz2();
346 j["sumxy"] = h.sumxy();
347 j["sumxz"] = h.sumxz();
348 j["sumyz"] = h.sumyz();
349 j["standard_deviationx"] = h.standard_deviationx();
350 j["standard_deviationy"] = h.standard_deviationy();
351 j["standard_deviationz"] = h.standard_deviationz();
352 }
353 };
354
356 template <unsigned int ND, atomicity Atomicity = atomicity::full, typename Arithmetic = double,
357 typename AxisTupleType = make_tuple_t<Axis<Arithmetic>, ND>>
360
361} // namespace Gaudi::Accumulators
void mergeAndReset(HistogramingAccumulatorInternal< ato, InputType, unsigned long, IntegralAccumulator, AxisTupleType > &other)
A base counter dealing with Histograms.
HistogramingAccumulatorInternal< Atomicity, InputType, unsigned long, IntegralAccumulator, AxisTupleType > Parent
SigmaNAccumulator< Arithmetic, Atomicity, ND > m_accumulator
HistoInputType< AxisToArithmetic_t< AxisTupleType >, ND > InputType
auto sums2() const
returns the nbentries, sums and "squared sums" of the inputs Practically we have first the number of ...
void mergeAndReset(RootHistogramingAccumulatorInternal< ato, Arithmetic, ND, AxisTupleType > &other)
RootHistogramingAccumulatorInternal & operator+=(typename InputType::ValueType v)
Extension of the standard Gaudi histogram to provide similar functionnality as ROOT.
friend void to_json(nlohmann::json &j, RootHistogramingCounterBase< 3, Atomicity, Arithmetic, Type, AxisTupleType > const &h)
friend void to_json(nlohmann::json &j, RootHistogramingCounterBase< 1, Atomicity, Arithmetic, Type, AxisTupleType > const &h)
HistogramingCounterBase< 3, Atomicity, Arithmetic, Type, RootHistogramingAccumulator, AxisTupleType > Parent
HistogramingCounterBase< 1, Atomicity, Arithmetic, Type, RootHistogramingAccumulator, AxisTupleType > Parent
HistogramingCounterBase< 2, Atomicity, Arithmetic, Type, RootHistogramingAccumulator, AxisTupleType > Parent
friend void to_json(nlohmann::json &j, RootHistogramingCounterBase< 2, Atomicity, Arithmetic, Type, AxisTupleType > const &h)
Efficient counter implementations for Gaudi.
void to_json(nlohmann::json &j, const Axis< Arithmetic > &axis)
automatic conversion of the Axis type to json
constexpr unsigned int NSUMS(unsigned int ND)
number of items in sums for a given dimension = 1 (nb items) + ND (sums of each dimension) + ND*(ND+1...
auto sqrt(std::chrono::duration< Rep, Period > d)
sqrt for std::chrono::duration
Definition Counters.h:34
atomicity
Defines atomicity of the accumulators.
RootHistogramingCounterBase< ND, Atomicity, Arithmetic, naming::histogramString, AxisTupleType > StaticRootHistogram
Root histograming counter. See RootHistogramingCounterBase for details.
void fetch_add(AtomicType &atVar, Arithmetic value)
generic fetch_add, also dealing with atomic types with no fetch_add member method
STL namespace.
small class used as InputType for regular Histograms basically a tuple of the given values,...
Class implementing a root histogram accumulator.
Small procyclass allowing operator[] to work as expected on the RootHistogram that is to return somet...
Proxy(RootHistogramingAccumulatorInternal &histo, typename InputType::ValueType &v)
std::array< Arithmetic, NSUMS(ND)> const sums() const
OutputTypeTS & operator=(OutputType const &other)
std::conditional_t< Atomicity==atomicity::full, OutputTypeTS, OutputType > InternalType
static constexpr OutputType DefaultValue()
std::conditional_t< ND==1, Arithmetic, std::array< Arithmetic, ND > > InputType
static void merge(InternalType &a, const OutputType &b) noexcept
static constexpr OutputType getValue(const InternalType &v) noexcept
static void merge(InternalType &a, InputType b) noexcept
std::array< Arithmetic, NSUMS(ND)> OutputType
static OutputType exchange(InternalType &v, OutputType newv) noexcept