File indexing completed on 2025-01-30 10:22:34
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #ifndef ROOT7_RHist
0017 #define ROOT7_RHist
0018
0019 #include "ROOT/RSpan.hxx"
0020 #include "ROOT/RAxis.hxx"
0021 #include "ROOT/RHistBinIter.hxx"
0022 #include "ROOT/RHistImpl.hxx"
0023 #include "ROOT/RHistData.hxx"
0024 #include "ROOT/RLogger.hxx"
0025 #include <initializer_list>
0026 #include <stdexcept>
0027
0028 namespace ROOT {
0029 namespace Experimental {
0030
0031
0032 template <int DIMENSIONS, class PRECISION, template <int D_, class P_> class... STAT>
0033 class RHist;
0034
0035
0036 template <int DIMENSIONS, class PRECISION, template <int D_, class P_> class... STAT>
0037 class RHist<DIMENSIONS, PRECISION, STAT...>
0038 HistFromImpl(std::unique_ptr<typename RHist<DIMENSIONS, PRECISION, STAT...>::ImplBase_t> pHistImpl);
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052 template <int DIMENSIONS, class PRECISION, template <int D_, class P_> class... STAT>
0053 class RHist {
0054 public:
0055
0056 using ImplBase_t =
0057 Detail::RHistImplBase<Detail::RHistData<DIMENSIONS, PRECISION, std::vector<PRECISION>, STAT...>>;
0058
0059 using CoordArray_t = typename ImplBase_t::CoordArray_t;
0060
0061 using Weight_t = PRECISION;
0062
0063 using FillFunc_t = typename ImplBase_t::FillFunc_t;
0064
0065 using AxisRange_t = typename ImplBase_t::AxisIterRange_t;
0066
0067 using const_iterator = Detail::RHistBinIter<ImplBase_t>;
0068
0069
0070 static constexpr int GetNDim() noexcept { return DIMENSIONS; }
0071
0072 RHist() = default;
0073 RHist(RHist &&) = default;
0074 RHist(const RHist &other): fImpl(other.fImpl->Clone()), fFillFunc(other.fFillFunc)
0075 {}
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092 explicit RHist(std::array<RAxisConfig, DIMENSIONS> axes);
0093
0094
0095 RHist(std::string_view histTitle, std::array<RAxisConfig, DIMENSIONS> axes);
0096
0097
0098 template <int ENABLEIF_NDIM = DIMENSIONS, class = typename std::enable_if<ENABLEIF_NDIM == 1>::type>
0099 explicit RHist(const RAxisConfig &xaxis): RHist(std::array<RAxisConfig, 1>{{xaxis}})
0100 {}
0101
0102
0103
0104 template <int ENABLEIF_NDIM = DIMENSIONS, class = typename std::enable_if<ENABLEIF_NDIM == 1>::type>
0105 RHist(std::string_view histTitle, const RAxisConfig &xaxis): RHist(histTitle, std::array<RAxisConfig, 1>{{xaxis}})
0106 {}
0107
0108
0109 template <int ENABLEIF_NDIM = DIMENSIONS, class = typename std::enable_if<ENABLEIF_NDIM == 2>::type>
0110 RHist(const RAxisConfig &xaxis, const RAxisConfig &yaxis): RHist(std::array<RAxisConfig, 2>{{xaxis, yaxis}})
0111 {}
0112
0113
0114
0115 template <int ENABLEIF_NDIM = DIMENSIONS, class = typename std::enable_if<ENABLEIF_NDIM == 2>::type>
0116 RHist(std::string_view histTitle, const RAxisConfig &xaxis, const RAxisConfig &yaxis)
0117 : RHist(histTitle, std::array<RAxisConfig, 2>{{xaxis, yaxis}})
0118 {}
0119
0120
0121 template <int ENABLEIF_NDIM = DIMENSIONS, class = typename std::enable_if<ENABLEIF_NDIM == 3>::type>
0122 RHist(const RAxisConfig &xaxis, const RAxisConfig &yaxis, const RAxisConfig &zaxis)
0123 : RHist(std::array<RAxisConfig, 3>{{xaxis, yaxis, zaxis}})
0124 {}
0125
0126
0127
0128 template <int ENABLEIF_NDIM = DIMENSIONS, class = typename std::enable_if<ENABLEIF_NDIM == 3>::type>
0129 RHist(std::string_view histTitle, const RAxisConfig &xaxis, const RAxisConfig &yaxis, const RAxisConfig &zaxis)
0130 : RHist(histTitle, std::array<RAxisConfig, 3>{{xaxis, yaxis, zaxis}})
0131 {}
0132
0133
0134 ImplBase_t *GetImpl() const noexcept { return fImpl.get(); }
0135
0136
0137 std::unique_ptr<ImplBase_t> TakeImpl() && noexcept { return std::move(fImpl); }
0138
0139
0140 void Fill(const CoordArray_t &x, Weight_t weight = (Weight_t)1) noexcept { (fImpl.get()->*fFillFunc)(x, weight); }
0141
0142
0143
0144
0145 void FillN(const std::span<const CoordArray_t> xN, const std::span<const Weight_t> weightN) noexcept
0146 {
0147 fImpl->FillN(xN, weightN);
0148 }
0149
0150
0151
0152
0153
0154 void FillN(std::initializer_list<const CoordArray_t> xN, std::initializer_list<const Weight_t> weightN) noexcept
0155 {
0156 fImpl->FillN(std::span<const CoordArray_t>(xN.begin(), xN.end()), std::span<const Weight_t>(weightN.begin(), weightN.end()));
0157 }
0158
0159
0160 void FillN(const std::span<const CoordArray_t> xN) noexcept { fImpl->FillN(xN); }
0161
0162
0163
0164 void FillN(std::initializer_list<const CoordArray_t> xN) noexcept {
0165 fImpl->FillN(std::span<const CoordArray_t>(xN.begin(), xN.end()));
0166 }
0167
0168
0169 int64_t GetEntries() const noexcept { return fImpl->GetStat().GetEntries(); }
0170
0171
0172 Weight_t GetBinContent(const CoordArray_t &x) const { return fImpl->GetBinContent(x); }
0173
0174
0175 double GetBinUncertainty(const CoordArray_t &x) const { return fImpl->GetBinUncertainty(x); }
0176
0177 const_iterator begin() const { return const_iterator(*fImpl, 1); }
0178
0179 const_iterator end() const { return const_iterator(*fImpl, fImpl->GetNBinsNoOver() + 1); }
0180
0181
0182
0183
0184 void swap(RHist<DIMENSIONS, PRECISION, STAT...> &other) noexcept
0185 {
0186 std::swap(fImpl, other.fImpl);
0187 std::swap(fFillFunc, other.fFillFunc);
0188 }
0189
0190 private:
0191
0192 std::unique_ptr<ImplBase_t> fImpl;
0193
0194
0195 FillFunc_t fFillFunc = nullptr;
0196
0197 friend RHist HistFromImpl<>(std::unique_ptr<ImplBase_t>);
0198 };
0199
0200
0201 template <int DIMENSIONS, class PRECISION>
0202 class RHist<DIMENSIONS, PRECISION>: public RHist<DIMENSIONS, PRECISION, RHistStatContent> {
0203 using RHist<DIMENSIONS, PRECISION, RHistStatContent>::RHist;
0204 };
0205
0206
0207
0208
0209 template <int DIMENSIONS, class PRECISION, template <int D_, class P_> class... STAT>
0210 void swap(RHist<DIMENSIONS, PRECISION, STAT...> &a, RHist<DIMENSIONS, PRECISION, STAT...> &b) noexcept
0211 {
0212 a.swap(b);
0213 }
0214
0215 namespace Internal {
0216
0217
0218
0219 template <int NDIM, int IDIM, class DATA, class... PROCESSEDAXISCONFIG>
0220 struct RHistImplGen {
0221
0222
0223 template <RAxisConfig::EKind KIND>
0224 std::unique_ptr<Detail::RHistImplBase<DATA>>
0225 MakeNextAxis(std::string_view title, const std::array<RAxisConfig, NDIM> &axes,
0226 PROCESSEDAXISCONFIG... processedAxisArgs)
0227 {
0228 using NextAxis_t = typename AxisConfigToType<KIND>::Axis_t;
0229 NextAxis_t nextAxis = AxisConfigToType<KIND>()(axes[IDIM]);
0230 using HistImpl_t = RHistImplGen<NDIM, IDIM + 1, DATA, PROCESSEDAXISCONFIG..., NextAxis_t>;
0231 return HistImpl_t()(title, axes, processedAxisArgs..., nextAxis);
0232 }
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246 std::unique_ptr<Detail::RHistImplBase<DATA>> operator()(std::string_view title,
0247 const std::array<RAxisConfig, NDIM> &axes,
0248 PROCESSEDAXISCONFIG... processedAxisArgs)
0249 {
0250 switch (axes[IDIM].GetKind()) {
0251 case RAxisConfig::kEquidistant: return MakeNextAxis<RAxisConfig::kEquidistant>(title, axes, processedAxisArgs...);
0252 case RAxisConfig::kGrow: return MakeNextAxis<RAxisConfig::kGrow>(title, axes, processedAxisArgs...);
0253 case RAxisConfig::kIrregular: return MakeNextAxis<RAxisConfig::kIrregular>(title, axes, processedAxisArgs...);
0254 default: R__LOG_ERROR(HistLog()) << "Unhandled axis kind";
0255 }
0256 return nullptr;
0257 }
0258 };
0259
0260
0261 template <int NDIM, class DATA, class... PROCESSEDAXISCONFIG>
0262
0263
0264 struct RHistImplGen<NDIM, NDIM, DATA, PROCESSEDAXISCONFIG...> {
0265 using HistImplBase_t = ROOT::Experimental::Detail::RHistImplBase<DATA>;
0266 std::unique_ptr<HistImplBase_t>
0267 operator()(std::string_view title, const std::array<RAxisConfig, DATA::GetNDim()> &, PROCESSEDAXISCONFIG... axisArgs)
0268 {
0269 using HistImplt_t = Detail::RHistImpl<DATA, PROCESSEDAXISCONFIG...>;
0270 return std::make_unique<HistImplt_t>(title, axisArgs...);
0271 }
0272 };
0273 }
0274
0275 template <int DIMENSIONS, class PRECISION, template <int D_, class P_> class... STAT>
0276 RHist<DIMENSIONS, PRECISION, STAT...>::RHist(std::string_view title, std::array<RAxisConfig, DIMENSIONS> axes)
0277 : fImpl{std::move(
0278 Internal::RHistImplGen<RHist::GetNDim(), 0,
0279 Detail::RHistData<DIMENSIONS, PRECISION, std::vector<PRECISION>, STAT...>>()(
0280 title, axes))}
0281 {
0282 fFillFunc = fImpl->GetFillFunc();
0283 }
0284
0285 template <int DIMENSIONS, class PRECISION, template <int D_, class P_> class... STAT>
0286 RHist<DIMENSIONS, PRECISION, STAT...>::RHist(std::array<RAxisConfig, DIMENSIONS> axes): RHist("", axes)
0287 {}
0288
0289
0290 template <int DIMENSIONS, class PRECISION, template <int D_, class P_> class... STAT>
0291 RHist<DIMENSIONS, PRECISION, STAT...>
0292 HistFromImpl(std::unique_ptr<typename RHist<DIMENSIONS, PRECISION, STAT...>::ImplBase_t> pHistImpl)
0293 {
0294 RHist<DIMENSIONS, PRECISION, STAT...> ret;
0295 ret.fFillFunc = pHistImpl->GetFillFunc();
0296 std::swap(ret.fImpl, pHistImpl);
0297 return ret;
0298 }
0299
0300
0301
0302
0303
0304 using RH1D = RHist<1, double, RHistStatContent, RHistStatUncertainty>;
0305 using RH1F = RHist<1, float, RHistStatContent, RHistStatUncertainty>;
0306 using RH1C = RHist<1, char, RHistStatContent>;
0307 using RH1I = RHist<1, int, RHistStatContent>;
0308 using RH1L = RHist<1, int64_t, RHistStatContent>;
0309 using RH1LL = RHist<1, int64_t, RHistStatContent>;
0310
0311 using RH2D = RHist<2, double, RHistStatContent, RHistStatUncertainty>;
0312 using RH2F = RHist<2, float, RHistStatContent, RHistStatUncertainty>;
0313 using RH2C = RHist<2, char, RHistStatContent>;
0314 using RH2I = RHist<2, int, RHistStatContent>;
0315 using RH2L = RHist<2, int64_t, RHistStatContent>;
0316 using RH2LL = RHist<2, int64_t, RHistStatContent>;
0317
0318 using RH3D = RHist<3, double, RHistStatContent, RHistStatUncertainty>;
0319 using RH3F = RHist<3, float, RHistStatContent, RHistStatUncertainty>;
0320 using RH3C = RHist<3, char, RHistStatContent>;
0321 using RH3I = RHist<3, int, RHistStatContent>;
0322 using RH3L = RHist<3, int64_t, RHistStatContent>;
0323 using RH3LL = RHist<3, int64_t, RHistStatContent>;
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339 template <int DIMENSIONS, class PRECISION,
0340 template <int D_, class P_> class... STAT_TO,
0341 template <int D_, class P_> class... STAT_FROM>
0342 void Add(RHist<DIMENSIONS, PRECISION, STAT_TO...> &to, const RHist<DIMENSIONS, PRECISION, STAT_FROM...> &from)
0343 {
0344
0345 auto& toImpl = *to.GetImpl();
0346 const auto& fromImpl = *from.GetImpl();
0347 for (int dim = 0; dim < DIMENSIONS; ++dim) {
0348 if (!toImpl.GetAxis(dim).HasSameBinningAs(fromImpl.GetAxis(dim))) {
0349 throw std::runtime_error("Attempted to add RHists with incompatible axis binning");
0350 }
0351 }
0352
0353
0354
0355 toImpl.GetStat().Add(fromImpl.GetStat());
0356 }
0357
0358 }
0359 }
0360
0361 #endif