File indexing completed on 2026-07-16 08:09:06
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/unit_test.hpp>
0010
0011 #include "ActsPlugins/Root/HistogramConverter.hpp"
0012
0013 #include <cmath>
0014 #include <random>
0015 #include <string>
0016 #include <vector>
0017
0018 #include <TEfficiency.h>
0019 #include <TH1F.h>
0020 #include <TH2F.h>
0021 #include <TProfile.h>
0022
0023 using namespace Acts;
0024 using namespace Acts::Experimental;
0025 using namespace ActsPlugins;
0026
0027 BOOST_AUTO_TEST_SUITE(HistogramConversionSuite)
0028
0029 namespace {
0030
0031 void testHist1D(const Histogram1& boostHist) {
0032 TH1F* rootHist = toRoot(boostHist);
0033
0034
0035 BOOST_CHECK_EQUAL(std::string(rootHist->GetName()), boostHist.name());
0036 BOOST_CHECK_EQUAL(std::string(rootHist->GetTitle()), boostHist.title());
0037
0038
0039 const auto& bh = boostHist.histogram();
0040 BOOST_CHECK_EQUAL(rootHist->GetNbinsX(), static_cast<int>(bh.axis(0).size()));
0041
0042
0043 for (int i = 1; i <= rootHist->GetNbinsX(); ++i) {
0044 BOOST_CHECK_CLOSE(rootHist->GetBinContent(i),
0045 static_cast<double>(bh.at(i - 1)), 1e-10);
0046 }
0047
0048 delete rootHist;
0049 }
0050
0051
0052 void testHist2D(const Histogram2& boostHist) {
0053 TH2F* rootHist = toRoot(boostHist);
0054
0055
0056 BOOST_CHECK_EQUAL(std::string(rootHist->GetName()), boostHist.name());
0057 BOOST_CHECK_EQUAL(std::string(rootHist->GetTitle()), boostHist.title());
0058
0059
0060 const auto& bh = boostHist.histogram();
0061 BOOST_CHECK_EQUAL(rootHist->GetNbinsX(), static_cast<int>(bh.axis(0).size()));
0062 BOOST_CHECK_EQUAL(rootHist->GetNbinsY(), static_cast<int>(bh.axis(1).size()));
0063
0064
0065 for (int i = 1; i <= rootHist->GetNbinsX(); ++i) {
0066 for (int j = 1; j <= rootHist->GetNbinsY(); ++j) {
0067 BOOST_CHECK_CLOSE(rootHist->GetBinContent(i, j),
0068 static_cast<double>(bh.at(i - 1, j - 1)), 1e-10);
0069 }
0070 }
0071
0072 delete rootHist;
0073 }
0074 }
0075
0076 BOOST_AUTO_TEST_CASE(Conversion_EmptyHistogram) {
0077 auto axis = AxisVariant(BoostRegularAxis(10, -10.0, 10.0, "x"));
0078 Histogram1 boostHist("empty", "Empty Histogram", {axis});
0079
0080 TH1F* rootHist = toRoot(boostHist);
0081
0082 BOOST_CHECK_EQUAL(rootHist->GetNbinsX(), 10);
0083 for (int i = 1; i <= rootHist->GetNbinsX(); ++i) {
0084 BOOST_CHECK_EQUAL(rootHist->GetBinContent(i), 0.0);
0085 }
0086
0087 delete rootHist;
0088 }
0089
0090 BOOST_AUTO_TEST_CASE(Conversion_Boost1D_to_ROOT_UniformBinning) {
0091 auto axis = AxisVariant(BoostRegularAxis(10, 0.0, 10.0, "x [cm]"));
0092 Histogram1 boostHist("test_hist", "Test Histogram", {axis});
0093
0094
0095 std::mt19937 rng(42);
0096 std::normal_distribution<double> dist(5.0, 1.0);
0097 for (int i = 0; i < 100; ++i) {
0098 boostHist.fill({dist(rng)});
0099 }
0100
0101 testHist1D(boostHist);
0102 }
0103
0104 BOOST_AUTO_TEST_CASE(Conversion_Boost1D_to_ROOT_VariableBinning) {
0105 std::vector<double> edges = {0.0, 0.5, 1.0, 2.0, 5.0, 10.0};
0106 auto axis = BoostVariableAxis(edges, "eta");
0107 Histogram1 boostHist("res_eta", "Residual vs Eta", {axis});
0108
0109
0110 boostHist.fill({0.3});
0111 boostHist.fill({0.3});
0112 boostHist.fill({1.5});
0113 boostHist.fill({3.0});
0114
0115 testHist1D(boostHist);
0116 }
0117
0118 BOOST_AUTO_TEST_CASE(Conversion_Boost2D_to_ROOT) {
0119 auto xAxis = BoostRegularAxis(10, -2.5, 2.5, "eta");
0120 auto yAxis = BoostRegularAxis(10, -5.0, 5.0, "residual");
0121 Histogram2 boostHist("res_vs_eta", "Residual vs Eta", {xAxis, yAxis});
0122
0123
0124 std::mt19937 rng(456);
0125 std::normal_distribution<double> etaDist(0.0, 1.0);
0126 std::normal_distribution<double> resDist(0.0, 2.0);
0127 for (int i = 0; i < 100; ++i) {
0128 boostHist.fill({etaDist(rng), resDist(rng)});
0129 }
0130
0131 testHist2D(boostHist);
0132 }
0133
0134 BOOST_AUTO_TEST_CASE(Conversion_Boost2D_to_ROOT_VariableBinning) {
0135 std::vector<double> etaEdges = {-2.5, -1.5, -0.5, 0.5, 1.5, 2.5};
0136 std::vector<double> ptEdges = {0.5, 1.0, 2.0, 5.0, 10.0};
0137
0138 auto xAxis = BoostVariableAxis(etaEdges, "eta");
0139 auto yAxis = BoostVariableAxis(ptEdges, "pT [GeV]");
0140 Histogram2 boostHist("eff_vs_eta_pt", "Efficiency vs Eta and pT",
0141 {xAxis, yAxis});
0142
0143 boostHist.fill({0.0, 3.0});
0144 boostHist.fill({-1.0, 7.0});
0145 boostHist.fill({2.0, 1.5});
0146
0147 testHist2D(boostHist);
0148 }
0149
0150 BOOST_AUTO_TEST_CASE(Conversion_BoostProfile_to_TProfile) {
0151 auto xAxis = BoostRegularAxis(10, -2.5, 2.5, "eta");
0152 ProfileHistogram1 profile("res_mean_vs_eta", "Mean Residual vs Eta", {xAxis},
0153 "residual [mm]");
0154
0155 std::map<double, double> expectedMeans;
0156
0157
0158 profile.fill({-2.0}, 1.0);
0159 profile.fill({-2.0}, 3.0);
0160 expectedMeans[-2.0] = 2.0;
0161
0162 profile.fill({0.0}, 5.0);
0163 profile.fill({0.0}, 7.0);
0164 expectedMeans[0.0] = 6.0;
0165
0166 profile.fill({2.0}, 9.0);
0167 profile.fill({2.0}, 11.0);
0168 profile.fill({2.0}, 13.0);
0169 expectedMeans[2.0] = 11.0;
0170
0171 TProfile* rootProfile = toRoot(profile);
0172
0173
0174 BOOST_CHECK_EQUAL(std::string(rootProfile->GetName()), "res_mean_vs_eta");
0175 BOOST_CHECK_EQUAL(std::string(rootProfile->GetTitle()),
0176 "Mean Residual vs Eta");
0177 BOOST_CHECK_EQUAL(std::string(rootProfile->GetXaxis()->GetTitle()), "eta");
0178 BOOST_CHECK_EQUAL(std::string(rootProfile->GetYaxis()->GetTitle()),
0179 "residual [mm]");
0180
0181
0182 BOOST_CHECK_EQUAL(rootProfile->GetNbinsX(), 10);
0183
0184
0185 const auto& bh = profile.histogram();
0186
0187 for (auto x : {-2.0, 0.0, 2.0}) {
0188 auto binIdx = bh.axis(0).index(x);
0189 BOOST_CHECK_CLOSE(rootProfile->GetBinContent(binIdx + 1),
0190 bh.at(binIdx).value(), 1e-6);
0191 BOOST_CHECK_CLOSE(rootProfile->GetBinContent(binIdx + 1),
0192 expectedMeans.at(x), 1e-6);
0193 }
0194
0195 delete rootProfile;
0196 }
0197
0198 BOOST_AUTO_TEST_CASE(Conversion_BoostProfile_to_TProfile_WithErrors) {
0199 auto xAxis = BoostRegularAxis(5, -2.5, 2.5, "eta");
0200
0201
0202 ProfileHistogram1 actsProfile("profile_test", "Profile Test", {xAxis},
0203 "value [units]");
0204
0205
0206 const auto& bh = actsProfile.histogram();
0207 const auto& axis = bh.axis(0);
0208 std::vector<double> edges(axis.size() + 1);
0209 for (int i = 0; i < axis.size(); ++i) {
0210 edges[i] = axis.bin(i).lower();
0211 }
0212 edges.back() = axis.bin(axis.size() - 1).upper();
0213 TProfile rootProfile("root_profile", "ROOT Profile", 5, edges.data());
0214 rootProfile.Sumw2();
0215
0216
0217 for (auto y : {10.0, 12.0, 14.0}) {
0218 rootProfile.Fill(-2.0, y);
0219 actsProfile.fill({-2.0}, y);
0220 }
0221
0222
0223 for (auto y : {5.0, 7.0}) {
0224 rootProfile.Fill(0.0, y);
0225 actsProfile.fill({0.0}, y);
0226 }
0227
0228
0229 for (auto y : {20.0, 22.0, 24.0, 26.0}) {
0230 rootProfile.Fill(1.5, y);
0231 actsProfile.fill({1.5}, y);
0232 }
0233
0234
0235 TProfile* convertedProfile = toRoot(actsProfile);
0236
0237
0238 BOOST_CHECK_EQUAL(convertedProfile->GetNbinsX(), rootProfile.GetNbinsX());
0239
0240
0241 for (int i = 0; i < axis.size(); ++i) {
0242 int rootBin = i + 1;
0243 const auto& acc = bh.at(i);
0244
0245
0246 BOOST_CHECK_EQUAL(convertedProfile->GetBinEntries(rootBin),
0247 rootProfile.GetBinEntries(rootBin));
0248 BOOST_CHECK_CLOSE(convertedProfile->GetBinEntries(rootBin), acc.count(),
0249 1e-10);
0250
0251
0252 BOOST_CHECK_CLOSE(convertedProfile->GetBinContent(rootBin),
0253 rootProfile.GetBinContent(rootBin), 1e-6);
0254 BOOST_CHECK_CLOSE(convertedProfile->GetBinContent(rootBin), acc.value(),
0255 1e-6);
0256
0257
0258 double rootError = rootProfile.GetBinError(rootBin);
0259 double convertedError = convertedProfile->GetBinError(rootBin);
0260 BOOST_CHECK_CLOSE(convertedError, rootError, 1e-6);
0261 }
0262
0263 delete convertedProfile;
0264 }
0265
0266 BOOST_AUTO_TEST_CASE(Conversion_Efficiency1D_to_TEfficiency) {
0267 auto axis = BoostRegularAxis(10, -3.0, 3.0, "eta");
0268 Efficiency1 eff("eff_vs_eta", "Efficiency vs Eta", {axis});
0269
0270
0271
0272 for (auto v : {true, true, true, false}) {
0273 eff.fill({0.5}, v);
0274 }
0275
0276
0277 for (auto v : {true, true, true, false, false, false}) {
0278 eff.fill({-1.5}, v);
0279 }
0280
0281 TEfficiency* rootEff = toRoot(eff);
0282
0283
0284 BOOST_CHECK_EQUAL(std::string(rootEff->GetName()), "eff_vs_eta");
0285 BOOST_CHECK_EQUAL(std::string(rootEff->GetTitle()), "Efficiency vs Eta");
0286
0287
0288 BOOST_CHECK_EQUAL(rootEff->GetTotalHistogram()->GetNbinsX(), 10);
0289
0290
0291 const auto& accepted = eff.acceptedHistogram();
0292 const auto& total = eff.totalHistogram();
0293
0294 for (auto x : {0.5, -1.5}) {
0295 auto binIdx = accepted.axis(0).index(x);
0296 double expectedEff = static_cast<double>(accepted.at(binIdx)) /
0297 static_cast<double>(total.at(binIdx));
0298 BOOST_CHECK_CLOSE(rootEff->GetEfficiency(binIdx + 1), expectedEff, 1e-6);
0299 }
0300
0301 delete rootEff;
0302 }
0303
0304 BOOST_AUTO_TEST_CASE(Conversion_Efficiency2D_to_TEfficiency) {
0305 auto xAxis = BoostRegularAxis(5, -2.5, 2.5, "eta");
0306 auto yAxis = BoostRegularAxis(5, 0.0, 5.0, "pt");
0307 Efficiency2 eff("eff_vs_eta_pt", "Efficiency vs Eta and pT", {xAxis, yAxis});
0308
0309
0310 for (auto v : {true, true, true, false}) {
0311 eff.fill({0.0, 2.5}, v);
0312 }
0313
0314
0315 for (auto v : {true, true, true, false, false, false}) {
0316 eff.fill({-1.5, 1.5}, v);
0317 }
0318
0319 TEfficiency* rootEff = toRoot(eff);
0320
0321
0322 BOOST_CHECK_EQUAL(std::string(rootEff->GetName()), "eff_vs_eta_pt");
0323 BOOST_CHECK_EQUAL(std::string(rootEff->GetTitle()),
0324 "Efficiency vs Eta and pT");
0325
0326
0327 BOOST_CHECK_EQUAL(rootEff->GetTotalHistogram()->GetNbinsX(), 5);
0328 BOOST_CHECK_EQUAL(rootEff->GetTotalHistogram()->GetNbinsY(), 5);
0329
0330
0331 const auto& accepted = eff.acceptedHistogram();
0332 const auto& total = eff.totalHistogram();
0333
0334 using P = std::pair<double, double>;
0335 for (auto coords : {P{0.0, 2.5}, P{-1.5, 1.5}}) {
0336 auto xIdx = accepted.axis(0).index(coords.first);
0337 auto yIdx = accepted.axis(1).index(coords.second);
0338 double expectedEff = static_cast<double>(accepted.at(xIdx, yIdx)) /
0339 static_cast<double>(total.at(xIdx, yIdx));
0340 int globalBin = rootEff->GetGlobalBin(static_cast<int>(xIdx + 1),
0341 static_cast<int>(yIdx + 1));
0342 BOOST_CHECK_CLOSE(rootEff->GetEfficiency(globalBin), expectedEff, 1e-6);
0343 }
0344
0345 delete rootEff;
0346 }
0347
0348 BOOST_AUTO_TEST_SUITE_END()