Logo ROOT  
Reference Guide
RHist.hxx
Go to the documentation of this file.
1 /// \file ROOT/RHist.hxx
2 /// \ingroup Hist ROOT7
3 /// \author Axel Naumann <axel@cern.ch>
4 /// \date 2015-03-23
5 /// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
6 /// is welcome!
7 
8 /*************************************************************************
9  * Copyright (C) 1995-2015, Rene Brun and Fons Rademakers. *
10  * All rights reserved. *
11  * *
12  * For the licensing terms see $ROOTSYS/LICENSE. *
13  * For the list of contributors see $ROOTSYS/README/CREDITS. *
14  *************************************************************************/
15 
16 #ifndef ROOT7_RHist
17 #define ROOT7_RHist
18 
19 #include "ROOT/RSpan.hxx"
20 #include "ROOT/RAxis.hxx"
21 #include "ROOT/RHistBinIter.hxx"
22 #include "ROOT/RHistImpl.hxx"
23 #include "ROOT/RHistData.hxx"
24 #include <initializer_list>
25 #include <stdexcept>
26 
27 namespace ROOT {
28 namespace Experimental {
29 
30 // fwd declare for fwd declare for friend declaration in RHist...
31 template <int DIMENSIONS, class PRECISION, template <int D_, class P_> class... STAT>
32 class RHist;
33 
34 // fwd declare for friend declaration in RHist.
35 template <int DIMENSIONS, class PRECISION, template <int D_, class P_> class... STAT>
36 class RHist<DIMENSIONS, PRECISION, STAT...>
37 HistFromImpl(std::unique_ptr<typename RHist<DIMENSIONS, PRECISION, STAT...>::ImplBase_t> pHistImpl);
38 
39 /**
40  \class RHist
41  Histogram class for histograms with `DIMENSIONS` dimensions, where each
42  bin count is stored by a value of type `PRECISION`. STAT stores statistical
43  data of the entries filled into the histogram (bin content, uncertainties etc).
44 
45  A histogram counts occurrences of values or n-dimensional combinations thereof.
46  Contrary to for instance a `RTree`, a histogram combines adjacent values. The
47  resolution of this combination is defined by the axis binning, see e.g.
48  http://www.wikiwand.com/en/Histogram
49  */
50 
51 template <int DIMENSIONS, class PRECISION, template <int D_, class P_> class... STAT>
52 class RHist {
53 public:
54  /// The type of the `Detail::RHistImplBase` of this histogram.
55  using ImplBase_t =
57  /// The coordinates type: a `DIMENSIONS`-dimensional `std::array` of `double`.
58  using CoordArray_t = typename ImplBase_t::CoordArray_t;
59  /// The type of weights
60  using Weight_t = PRECISION;
61  /// Pointer type to `HistImpl_t::Fill`, for faster access.
62  using FillFunc_t = typename ImplBase_t::FillFunc_t;
63  /// Range.
65 
67 
68  /// Number of dimensions of the coordinates
69  static constexpr int GetNDim() noexcept { return DIMENSIONS; }
70 
71  RHist() = default;
72  RHist(RHist &&) = default;
73  RHist(const RHist &other): fImpl(other.fImpl->Clone()), fFillFunc(other.fFillFunc)
74  {}
75 
76  /// Create a histogram from an `array` of axes (`RAxisConfig`s). Example code:
77  ///
78  /// Construct a 1-dimensional histogram that can be filled with `floats`s.
79  /// The axis has 10 bins between 0. and 1. The two outermost sets of curly
80  /// braces are to reach the initialization of the `std::array` elements; the
81  /// inner one is for the initialization of a `RAxisCoordinate`.
82  ///
83  /// RHist<1,float> h1f({{ {10, 0., 1.} }});
84  ///
85  /// Construct a 2-dimensional histogram, with the first axis as before, and
86  /// the second axis having non-uniform ("irregular") binning, where all bin-
87  /// edges are specified. As this is itself an array it must be enclosed by
88  /// double curlies.
89  ///
90  /// RHist<2,int> h2i({{ {10, 0., 1.}, {{-1., 0., 1., 10., 100.}} }});
91  explicit RHist(std::array<RAxisConfig, DIMENSIONS> axes);
92 
93  /// Constructor overload taking the histogram title.
94  RHist(std::string_view histTitle, std::array<RAxisConfig, DIMENSIONS> axes);
95 
96  /// Constructor overload that's only available for a 1-dimensional histogram.
98  explicit RHist(const RAxisConfig &xaxis): RHist(std::array<RAxisConfig, 1>{{xaxis}})
99  {}
100 
101  /// Constructor overload that's only available for a 1-dimensional histogram,
102  /// also passing the histogram title.
104  RHist(std::string_view histTitle, const RAxisConfig &xaxis): RHist(histTitle, std::array<RAxisConfig, 1>{{xaxis}})
105  {}
106 
107  /// Constructor overload that's only available for a 2-dimensional histogram.
109  RHist(const RAxisConfig &xaxis, const RAxisConfig &yaxis): RHist(std::array<RAxisConfig, 2>{{xaxis, yaxis}})
110  {}
111 
112  /// Constructor overload that's only available for a 2-dimensional histogram,
113  /// also passing the histogram title.
115  RHist(std::string_view histTitle, const RAxisConfig &xaxis, const RAxisConfig &yaxis)
116  : RHist(histTitle, std::array<RAxisConfig, 2>{{xaxis, yaxis}})
117  {}
118 
119  /// Constructor overload that's only available for a 3-dimensional histogram.
121  RHist(const RAxisConfig &xaxis, const RAxisConfig &yaxis, const RAxisConfig &zaxis)
122  : RHist(std::array<RAxisConfig, 3>{{xaxis, yaxis, zaxis}})
123  {}
124 
125  /// Constructor overload that's only available for a 3-dimensional histogram,
126  /// also passing the histogram title.
128  RHist(std::string_view histTitle, const RAxisConfig &xaxis, const RAxisConfig &yaxis, const RAxisConfig &zaxis)
129  : RHist(histTitle, std::array<RAxisConfig, 3>{{xaxis, yaxis, zaxis}})
130  {}
131 
132  /// Access the ImplBase_t this RHist points to.
133  ImplBase_t *GetImpl() const noexcept { return fImpl.get(); }
134 
135  /// "Steal" the ImplBase_t this RHist points to.
136  std::unique_ptr<ImplBase_t> TakeImpl() && noexcept { return std::move(fImpl); }
137 
138  /// Add `weight` to the bin containing coordinate `x`.
139  void Fill(const CoordArray_t &x, Weight_t weight = (Weight_t)1) noexcept { (fImpl.get()->*fFillFunc)(x, weight); }
140 
141  /// For each coordinate in `xN`, add `weightN[i]` to the bin at coordinate
142  /// `xN[i]`. The sizes of `xN` and `weightN` must be the same. This is more
143  /// efficient than many separate calls to `Fill()`.
144  void FillN(const std::span<const CoordArray_t> xN, const std::span<const Weight_t> weightN) noexcept
145  {
146  fImpl->FillN(xN, weightN);
147  }
148 
149  /// Convenience overload: `FillN()` with weight 1.
150  void FillN(const std::span<const CoordArray_t> xN) noexcept { fImpl->FillN(xN); }
151 
152  /// Get the number of entries this histogram was filled with.
153  int64_t GetEntries() const noexcept { return fImpl->GetStat().GetEntries(); }
154 
155  /// Get the content of the bin at `x`.
156  Weight_t GetBinContent(const CoordArray_t &x) const { return fImpl->GetBinContent(x); }
157 
158  /// Get the uncertainty on the content of the bin at `x`.
159  double GetBinUncertainty(const CoordArray_t &x) const { return fImpl->GetBinUncertainty(x); }
160 
161  const_iterator begin() const { return const_iterator(*fImpl); }
162 
163  const_iterator end() const { return const_iterator(*fImpl, fImpl->GetNBinsNoOver()); }
164 
165  /// Swap *this and other.
166  ///
167  /// Very efficient; swaps the `fImpl` pointers.
169  {
170  std::swap(fImpl, other.fImpl);
171  std::swap(fFillFunc, other.fFillFunc);
172  }
173 
174 private:
175  /// The actual histogram implementation.
176  std::unique_ptr<ImplBase_t> fImpl;
177 
178  /// Pointer to RHistImpl::Fill() member function.
179  FillFunc_t fFillFunc = nullptr; //!
180 
181  friend RHist HistFromImpl<>(std::unique_ptr<ImplBase_t>);
182 };
183 
184 /// RHist with no STAT parameter uses RHistStatContent by default.
185 template <int DIMENSIONS, class PRECISION>
186 class RHist<DIMENSIONS, PRECISION>: public RHist<DIMENSIONS, PRECISION, RHistStatContent> {
188 };
189 
190 /// Swap two histograms.
191 ///
192 /// Very efficient; swaps the `fImpl` pointers.
193 template <int DIMENSIONS, class PRECISION, template <int D_, class P_> class... STAT>
195 {
196  a.swap(b);
197 };
198 
199 namespace Internal {
200 /**
201  Generate RHist::fImpl from RHist constructor arguments.
202  */
203 template <int NDIM, int IDIM, class DATA, class... PROCESSEDAXISCONFIG>
204 struct RHistImplGen {
205  /// Select the template argument for the next axis type, and "recurse" into
206  /// RHistImplGen for the next axis.
207  template <RAxisConfig::EKind KIND>
208  std::unique_ptr<Detail::RHistImplBase<DATA>>
209  MakeNextAxis(std::string_view title, const std::array<RAxisConfig, NDIM> &axes,
210  PROCESSEDAXISCONFIG... processedAxisArgs)
211  {
212  using NextAxis_t = typename AxisConfigToType<KIND>::Axis_t;
213  NextAxis_t nextAxis = AxisConfigToType<KIND>()(axes[IDIM]);
214  using HistImpl_t = RHistImplGen<NDIM, IDIM + 1, DATA, PROCESSEDAXISCONFIG..., NextAxis_t>;
215  return HistImpl_t()(title, axes, processedAxisArgs..., nextAxis);
216  }
217 
218  /// Make a RHistImpl-derived object reflecting the RAxisConfig array.
219  ///
220  /// Delegate to the appropriate MakeNextAxis instantiation, depending on the
221  /// axis type selected in the RAxisConfig.
222  /// \param title - title of the derived object.
223  /// \param axes - `RAxisConfig` objects describing the axis of the resulting
224  /// RHistImpl.
225  /// \param processedAxisArgs - the RAxisBase-derived axis objects describing the
226  /// axes of the resulting RHistImpl. There are `IDIM` of those; in the end
227  /// (`IDIM` == `GetNDim()`), all `axes` have been converted to
228  /// `processedAxisArgs` and the RHistImpl constructor can be invoked, passing
229  /// the `processedAxisArgs`.
230  std::unique_ptr<Detail::RHistImplBase<DATA>> operator()(std::string_view title,
231  const std::array<RAxisConfig, NDIM> &axes,
232  PROCESSEDAXISCONFIG... processedAxisArgs)
233  {
234  switch (axes[IDIM].GetKind()) {
235  case RAxisConfig::kEquidistant: return MakeNextAxis<RAxisConfig::kEquidistant>(title, axes, processedAxisArgs...);
236  case RAxisConfig::kGrow: return MakeNextAxis<RAxisConfig::kGrow>(title, axes, processedAxisArgs...);
237  case RAxisConfig::kIrregular: return MakeNextAxis<RAxisConfig::kIrregular>(title, axes, processedAxisArgs...);
238  default: R__ERROR_HERE("HIST") << "Unhandled axis kind";
239  }
240  return nullptr;
241  }
242 };
243 
244 /// Generate RHist::fImpl from constructor arguments; recursion end.
245 template <int NDIM, class DATA, class... PROCESSEDAXISCONFIG>
246 /// Create the histogram, now that all axis types and initializer objects are
247 /// determined.
248 struct RHistImplGen<NDIM, NDIM, DATA, PROCESSEDAXISCONFIG...> {
250  std::unique_ptr<HistImplBase_t>
251  operator()(std::string_view title, const std::array<RAxisConfig, DATA::GetNDim()> &, PROCESSEDAXISCONFIG... axisArgs)
252  {
253  using HistImplt_t = Detail::RHistImpl<DATA, PROCESSEDAXISCONFIG...>;
254  return std::make_unique<HistImplt_t>(title, axisArgs...);
255  }
256 };
257 } // namespace Internal
258 
259 template <int DIMENSIONS, class PRECISION, template <int D_, class P_> class... STAT>
260 RHist<DIMENSIONS, PRECISION, STAT...>::RHist(std::string_view title, std::array<RAxisConfig, DIMENSIONS> axes)
261  : fImpl{std::move(
263  Detail::RHistData<DIMENSIONS, PRECISION, std::vector<PRECISION>, STAT...>>()(
264  title, axes))}
265 {
266  fFillFunc = fImpl->GetFillFunc();
267 }
268 
269 template <int DIMENSIONS, class PRECISION, template <int D_, class P_> class... STAT>
270 RHist<DIMENSIONS, PRECISION, STAT...>::RHist(std::array<RAxisConfig, DIMENSIONS> axes): RHist("", axes)
271 {}
272 
273 /// Adopt an external, stand-alone RHistImpl. The RHist will take ownership.
274 template <int DIMENSIONS, class PRECISION, template <int D_, class P_> class... STAT>
275 RHist<DIMENSIONS, PRECISION, STAT...>
276 HistFromImpl(std::unique_ptr<typename RHist<DIMENSIONS, PRECISION, STAT...>::ImplBase_t> pHistImpl)
277 {
278  RHist<DIMENSIONS, PRECISION, STAT...> ret;
279  ret.fFillFunc = pHistImpl->GetFillFunc();
280  std::swap(ret.fImpl, pHistImpl);
281  return ret;
282 };
283 
284 /// \name RHist Typedefs
285 ///\{ Convenience typedefs (ROOT6-compatible type names)
286 
287 // Keep them as typedefs, to make sure old-style documentation tools can understand them.
293 
299 
305 ///\}
306 
307 /// Add two histograms.
308 ///
309 /// This operation may currently only be performed if the two histograms have
310 /// the same axis configuration, use the same precision, and if `from` records
311 /// at least the same statistics as `to` (recording more stats is fine).
312 ///
313 /// Adding histograms with incompatible axis binning will be reported at runtime
314 /// with an `std::runtime_error`. Insufficient statistics in the source
315 /// histogram will be detected at compile-time and result in a compiler error.
316 ///
317 /// In the future, we may either adopt a more relaxed definition of histogram
318 /// addition or provide a mechanism to convert from one histogram type to
319 /// another. We currently favor the latter path.
320 template <int DIMENSIONS, class PRECISION,
321  template <int D_, class P_> class... STAT_TO,
322  template <int D_, class P_> class... STAT_FROM>
324 {
325  // Enforce "same axis configuration" policy.
326  auto& toImpl = *to.GetImpl();
327  const auto& fromImpl = *from.GetImpl();
328  for (int dim = 0; dim < DIMENSIONS; ++dim) {
329  if (!toImpl.GetAxis(dim).HasSameBinningAs(fromImpl.GetAxis(dim))) {
330  throw std::runtime_error("Attempted to add RHists with incompatible axis binning");
331  }
332  }
333 
334  // Now that we know that the two axes have the same binning, we can just add
335  // the statistics directly.
336  toImpl.GetStat().Add(fromImpl.GetStat());
337 }
338 
339 } // namespace Experimental
340 } // namespace ROOT
341 
342 #endif
ROOT::Experimental::RHist::RHist
RHist(const RAxisConfig &xaxis, const RAxisConfig &yaxis)
Constructor overload that's only available for a 2-dimensional histogram.
Definition: RHist.hxx:121
ROOT::Experimental::RHist::Weight_t
PRECISION Weight_t
The type of weights.
Definition: RHist.hxx:72
ROOT::Experimental::HistFromImpl
class RHist< DIMENSIONS, PRECISION, STAT... > HistFromImpl(std::unique_ptr< typename RHist< DIMENSIONS, PRECISION, STAT... >::ImplBase_t > pHistImpl)
Adopt an external, stand-alone RHistImpl. The RHist will take ownership.
Definition: RHist.hxx:288
ROOT::Experimental::RHist::FillFunc_t
typename ImplBase_t::FillFunc_t FillFunc_t
Pointer type to HistImpl_t::Fill, for faster access.
Definition: RHist.hxx:74
RAxis.hxx
ROOT::Experimental::RAxisConfig::kGrow
@ kGrow
represents a RAxisGrow
Definition: RAxisConfig.hxx:51
ROOT::Experimental::Detail::RHistBinIter
Definition: RHistBinIter.hxx:115
ROOT::Experimental::RAxisConfig
Definition: RAxisConfig.hxx:47
ROOT::Experimental::RHist::end
const_iterator end() const
Definition: RHist.hxx:175
Axis_t
double Axis_t
Definition: RtypesCore.h:76
ROOT::Experimental::RHist::TakeImpl
std::unique_ptr< ImplBase_t > TakeImpl() &&noexcept
"Steal" the ImplBase_t this RHist points to.
Definition: RHist.hxx:148
ROOT::Experimental::RHist::GetBinUncertainty
double GetBinUncertainty(const CoordArray_t &x) const
Get the uncertainty on the content of the bin at x.
Definition: RHist.hxx:171
string_view
basic_string_view< char > string_view
Definition: libcpp_string_view.h:785
x
Double_t x[n]
Definition: legend1.C:17
ROOT::Experimental::RAxisConfig::kEquidistant
@ kEquidistant
represents a RAxisEquidistant
Definition: RAxisConfig.hxx:50
ROOT::Experimental::Internal::RHistImplGen::MakeNextAxis
std::unique_ptr< Detail::RHistImplBase< DATA > > MakeNextAxis(std::string_view title, const std::array< RAxisConfig, NDIM > &axes, PROCESSEDAXISCONFIG... processedAxisArgs)
Select the template argument for the next axis type, and "recurse" into RHistImplGen for the next axi...
Definition: RHist.hxx:221
b
#define b(i)
Definition: RSha256.hxx:118
ROOT::Experimental::Detail::RHistImpl
Definition: RHistImpl.hxx:721
ROOT::Experimental::RAxisConfig::kIrregular
@ kIrregular
represents a RAxisIrregular
Definition: RAxisConfig.hxx:52
ROOT::Experimental::Internal::RHistImplGen::operator()
std::unique_ptr< Detail::RHistImplBase< DATA > > operator()(std::string_view title, const std::array< RAxisConfig, NDIM > &axes, PROCESSEDAXISCONFIG... processedAxisArgs)
Make a RHistImpl-derived object reflecting the RAxisConfig array.
Definition: RHist.hxx:242
ROOT::Experimental::RHist::CoordArray_t
typename ImplBase_t::CoordArray_t CoordArray_t
The coordinates type: a DIMENSIONS-dimensional std::array of double.
Definition: RHist.hxx:70
RHistImpl.hxx
ROOT::Experimental::RHist::GetImpl
ImplBase_t * GetImpl() const noexcept
Access the ImplBase_t this RHist points to.
Definition: RHist.hxx:145
RHistBinIter.hxx
ROOT::Experimental::RHist::Fill
void Fill(const CoordArray_t &x, Weight_t weight=(Weight_t) 1) noexcept
Add weight to the bin containing coordinate x.
Definition: RHist.hxx:151
ROOT::Experimental::Detail::RHistData
Definition: RHistData.hxx:522
ROOT::Experimental::RHist::swap
void swap(RHist< DIMENSIONS, PRECISION, STAT... > &other) noexcept
Swap *this and other.
Definition: RHist.hxx:180
R__ERROR_HERE
#define R__ERROR_HERE(GROUP)
Definition: RLogger.hxx:183
ROOT::Experimental::Detail::RHistImplBase
Definition: RHistImpl.hxx:151
ROOT::Experimental::RHist::ImplBase_t
Detail::RHistImplBase< Detail::RHistData< DIMENSIONS, PRECISION, std::vector< PRECISION >, STAT... > > ImplBase_t
The type of the Detail::RHistImplBase of this histogram.
Definition: RHist.hxx:68
ROOT::Experimental::RHist::GetNDim
static constexpr int GetNDim() noexcept
Number of dimensions of the coordinates.
Definition: RHist.hxx:81
a
auto * a
Definition: textangle.C:12
ROOT::Experimental::RHist::RHist
RHist()=default
STAT
ROOT::Experimental::RHist::GetBinContent
Weight_t GetBinContent(const CoordArray_t &x) const
Get the content of the bin at x.
Definition: RHist.hxx:168
ROOT::Experimental::RHist::fImpl
std::unique_ptr< ImplBase_t > fImpl
The actual histogram implementation.
Definition: RHist.hxx:188
ROOT::Experimental::Internal::RHistImplGen
Generate RHist::fImpl from RHist constructor arguments.
Definition: RHist.hxx:216
ROOT::Experimental::RHist::FillN
void FillN(const std::span< const CoordArray_t > xN, const std::span< const Weight_t > weightN) noexcept
For each coordinate in xN, add weightN[i] to the bin at coordinate xN[i].
Definition: RHist.hxx:156
ROOT::Experimental::RHist::const_iterator
Detail::RHistBinIter< ImplBase_t > const_iterator
Definition: RHist.hxx:78
ROOT::Experimental::RHist::AxisRange_t
typename ImplBase_t::AxisIterRange_t AxisRange_t
Range.
Definition: RHist.hxx:76
ROOT::Experimental::swap
void swap(RHist< DIMENSIONS, PRECISION, STAT... > &a, RHist< DIMENSIONS, PRECISION, STAT... > &b) noexcept
Swap two histograms.
Definition: RHist.hxx:206
ROOT::Experimental::Detail::RHistImplBase::CoordArray_t
Hist::CoordArray_t< DATA::GetNDim()> CoordArray_t
Type of the coordinates.
Definition: RHistImpl.hxx:156
ROOT::Experimental::RHist::fFillFunc
FillFunc_t fFillFunc
Pointer to RHistImpl::Fill() member function.
Definition: RHist.hxx:191
RHistData.hxx
ROOT::Experimental::Detail::RHistImplBase::FillFunc_t
void(RHistImplBase::*)(const CoordArray_t &x, Weight_t w) FillFunc_t
Type of the Fill(x, w) function.
Definition: RHistImpl.hxx:163
ROOT::Experimental::RHist::GetEntries
int64_t GetEntries() const noexcept
Get the number of entries this histogram was filled with.
Definition: RHist.hxx:165
ROOT::Experimental::Detail::RHistImplPrecisionAgnosticBase< DATA::GetNDim()>::AxisIterRange_t
Hist::AxisIterRange_t< DIMENSIONS > AxisIterRange_t
Range type.
Definition: RHistImpl.hxx:78
ROOT::Experimental::RHist
Definition: RHist.hxx:44
ROOT::Experimental::Add
void Add(RHist< DIMENSIONS, PRECISION, STAT_TO... > &to, const RHist< DIMENSIONS, PRECISION, STAT_FROM... > &from)
Add two histograms.
Definition: RHist.hxx:335
PRECISION
#define PRECISION
Definition: MnPrint.cxx:26
ROOT::Experimental::RHist::begin
const_iterator begin() const
Definition: RHist.hxx:173
type
int type
Definition: TGX11.cxx:121
RSpan.hxx
ROOT
VSD Structures.
Definition: StringConv.hxx:21