File indexing completed on 2026-04-17 07:47:22
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsPlugins/Root/HistogramConverter.hpp"
0010
0011 #include <cstddef>
0012 #include <format>
0013 #include <vector>
0014
0015 #include <TEfficiency.h>
0016 #include <TFitResult.h>
0017 #include <TGraphAsymmErrors.h>
0018 #include <TH1F.h>
0019 #include <TH2F.h>
0020 #include <TH3F.h>
0021 #include <TProfile.h>
0022 #include <boost/histogram/accumulators/weighted_sum.hpp>
0023
0024 using namespace Acts::Experimental;
0025
0026 std::unique_ptr<TH1F> ActsPlugins::toRoot(const Histogram1& boostHist) {
0027 const auto& bh = boostHist.histogram();
0028 const auto& axis = bh.axis(0);
0029
0030
0031 std::vector<double> edges = extractBinEdges(axis);
0032
0033
0034 auto rootHist = std::make_unique<TH1F>(boostHist.name().c_str(),
0035 boostHist.title().c_str(), axis.size(),
0036 edges.data());
0037
0038
0039 for (auto&& x : boost::histogram::indexed(bh)) {
0040
0041 double content = *x;
0042
0043
0044 int rootBinIndex = x.index(0) + 1;
0045 rootHist->SetBinContent(rootBinIndex, content);
0046 }
0047
0048
0049 rootHist->GetXaxis()->SetTitle(axis.metadata().c_str());
0050
0051 return rootHist;
0052 }
0053
0054 std::unique_ptr<TH2F> ActsPlugins::toRoot(const Histogram2& boostHist) {
0055 const auto& bh = boostHist.histogram();
0056 const auto& xAxis = bh.axis(0);
0057 const auto& yAxis = bh.axis(1);
0058
0059
0060 std::vector<double> xEdges = extractBinEdges(xAxis);
0061
0062
0063 std::vector<double> yEdges = extractBinEdges(yAxis);
0064
0065
0066 auto rootHist = std::make_unique<TH2F>(
0067 boostHist.name().c_str(), boostHist.title().c_str(), xAxis.size(),
0068 xEdges.data(), yAxis.size(), yEdges.data());
0069
0070
0071 for (auto&& x : boost::histogram::indexed(bh)) {
0072
0073 double content = *x;
0074
0075
0076
0077 int rootXBin = x.index(0) + 1;
0078 int rootYBin = x.index(1) + 1;
0079 rootHist->SetBinContent(rootXBin, rootYBin, content);
0080 }
0081
0082
0083 rootHist->GetXaxis()->SetTitle(xAxis.metadata().c_str());
0084 rootHist->GetYaxis()->SetTitle(yAxis.metadata().c_str());
0085
0086 return rootHist;
0087 }
0088
0089 std::unique_ptr<TH3F> ActsPlugins::toRoot(const Histogram3& boostHist) {
0090 const auto& bh = boostHist.histogram();
0091 const auto& xAxis = bh.axis(0);
0092 const auto& yAxis = bh.axis(1);
0093 const auto& zAxis = bh.axis(2);
0094
0095
0096 std::vector<double> xEdges = extractBinEdges(xAxis);
0097
0098
0099 std::vector<double> yEdges = extractBinEdges(yAxis);
0100
0101
0102 std::vector<double> zEdges = extractBinEdges(zAxis);
0103
0104
0105 auto rootHist = std::make_unique<TH3F>(
0106 boostHist.name().c_str(), boostHist.title().c_str(), xAxis.size(),
0107 xEdges.data(), yAxis.size(), yEdges.data(), zAxis.size(), zEdges.data());
0108
0109
0110 for (auto&& x : boost::histogram::indexed(bh)) {
0111
0112 double content = *x;
0113
0114
0115
0116 int rootXBin = x.index(0) + 1;
0117 int rootYBin = x.index(1) + 1;
0118 int rootZBin = x.index(2) + 1;
0119 rootHist->SetBinContent(rootXBin, rootYBin, rootZBin, content);
0120 }
0121
0122
0123 rootHist->GetXaxis()->SetTitle(xAxis.metadata().c_str());
0124 rootHist->GetYaxis()->SetTitle(yAxis.metadata().c_str());
0125 rootHist->GetZaxis()->SetTitle(zAxis.metadata().c_str());
0126
0127 return rootHist;
0128 }
0129
0130 std::unique_ptr<TProfile> ActsPlugins::toRoot(
0131 const ProfileHistogram1& boostProfile) {
0132 const auto& bh = boostProfile.histogram();
0133 const auto& axis = bh.axis(0);
0134
0135
0136 std::vector<double> edges = extractBinEdges(axis);
0137
0138
0139 auto rootProfile = std::make_unique<TProfile>(boostProfile.name().c_str(),
0140 boostProfile.title().c_str(),
0141 axis.size(), edges.data());
0142
0143
0144 rootProfile->Sumw2();
0145
0146
0147
0148
0149
0150
0151 using Accumulator = boost::histogram::accumulators::mean<double>;
0152
0153 for (auto&& x : boost::histogram::indexed(bh)) {
0154 const Accumulator& acc = *x;
0155
0156
0157 int rootBinIndex = x.index(0) + 1;
0158
0159 double count = acc.count();
0160
0161 if (count == 0) {
0162 continue;
0163 }
0164 double mean = acc.value();
0165 double variance = acc.variance();
0166
0167
0168
0169
0170
0171
0172
0173 double sum = mean * count;
0174
0175
0176
0177
0178 double sumOfSquares = (count - 1.0) * variance + count * mean * mean;
0179
0180
0181 rootProfile->SetBinContent(rootBinIndex, sum);
0182 rootProfile->SetBinEntries(rootBinIndex, count);
0183
0184
0185
0186 TArrayD* sumw2 = rootProfile->GetSumw2();
0187 TArrayD* binSumw2 = rootProfile->GetBinSumw2();
0188
0189 assert(sumw2 && "Sumw2 is null");
0190 assert(binSumw2 && "BinSumw2 is null");
0191
0192
0193 sumw2->fArray[rootBinIndex] = sumOfSquares;
0194
0195 binSumw2->fArray[rootBinIndex] = count;
0196 }
0197
0198
0199 rootProfile->GetXaxis()->SetTitle(axis.metadata().c_str());
0200
0201 rootProfile->GetYaxis()->SetTitle(boostProfile.sampleAxisTitle().c_str());
0202
0203 return rootProfile;
0204 }
0205
0206 std::unique_ptr<TEfficiency> ActsPlugins::toRoot(const Efficiency1& boostEff) {
0207 const auto& accepted = boostEff.acceptedHistogram();
0208 const auto& total = boostEff.totalHistogram();
0209 const auto& axis = accepted.axis(0);
0210
0211
0212 std::vector<double> edges = extractBinEdges(axis);
0213
0214
0215 auto acceptedHist =
0216 std::make_unique<TH1F>((boostEff.name() + "_accepted").c_str(), "Passed",
0217 axis.size(), edges.data());
0218
0219 auto totalHist = std::make_unique<TH1F>((boostEff.name() + "_total").c_str(),
0220 "Total", axis.size(), edges.data());
0221
0222
0223 for (int i = 0; i < axis.size(); ++i) {
0224 auto acceptedCount = static_cast<double>(accepted.at(i));
0225 auto totalCount = static_cast<double>(total.at(i));
0226
0227 acceptedHist->SetBinContent(i + 1, acceptedCount);
0228 totalHist->SetBinContent(i + 1, totalCount);
0229 }
0230
0231
0232 acceptedHist->GetXaxis()->SetTitle(axis.metadata().c_str());
0233 totalHist->GetXaxis()->SetTitle(axis.metadata().c_str());
0234
0235
0236
0237 totalHist->GetYaxis()->SetTitle("Efficiency");
0238
0239
0240
0241 auto rootEff = std::make_unique<TEfficiency>(*acceptedHist, *totalHist);
0242 rootEff->SetName(boostEff.name().c_str());
0243 rootEff->SetTitle(boostEff.title().c_str());
0244
0245 return rootEff;
0246 }
0247
0248 std::unique_ptr<TEfficiency> ActsPlugins::toRoot(const Efficiency2& boostEff) {
0249 const auto& accepted = boostEff.acceptedHistogram();
0250 const auto& total = boostEff.totalHistogram();
0251 const auto& xAxis = accepted.axis(0);
0252 const auto& yAxis = accepted.axis(1);
0253
0254
0255 std::vector<double> xEdges = extractBinEdges(xAxis);
0256
0257
0258 std::vector<double> yEdges = extractBinEdges(yAxis);
0259
0260
0261 auto acceptedHist = std::make_unique<TH2F>(
0262 (boostEff.name() + "_accepted").c_str(), "Accepted", xAxis.size(),
0263 xEdges.data(), yAxis.size(), yEdges.data());
0264
0265 auto totalHist = std::make_unique<TH2F>((boostEff.name() + "_total").c_str(),
0266 "Total", xAxis.size(), xEdges.data(),
0267 yAxis.size(), yEdges.data());
0268
0269
0270 for (int i = 0; i < xAxis.size(); ++i) {
0271 for (int j = 0; j < yAxis.size(); ++j) {
0272 auto acceptedCount = static_cast<double>(accepted.at(i, j));
0273 auto totalCount = total.at(i, j);
0274
0275 acceptedHist->SetBinContent(i + 1, j + 1, acceptedCount);
0276 totalHist->SetBinContent(i + 1, j + 1, totalCount);
0277 }
0278 }
0279
0280
0281 acceptedHist->GetXaxis()->SetTitle(xAxis.metadata().c_str());
0282 totalHist->GetXaxis()->SetTitle(xAxis.metadata().c_str());
0283
0284
0285 acceptedHist->GetYaxis()->SetTitle(yAxis.metadata().c_str());
0286 totalHist->GetYaxis()->SetTitle(yAxis.metadata().c_str());
0287
0288
0289
0290 totalHist->GetZaxis()->SetTitle("Efficiency");
0291
0292
0293
0294 auto rootEff = std::make_unique<TEfficiency>(*acceptedHist, *totalHist);
0295 rootEff->SetName(boostEff.name().c_str());
0296 rootEff->SetTitle(boostEff.title().c_str());
0297
0298 return rootEff;
0299 }
0300
0301 std::tuple<std::unique_ptr<TH1F>, std::unique_ptr<TH1F>, double>
0302 ActsPlugins::extractMeanWidthProfiles(const TH2F& hist2d,
0303 const std::string& meanName,
0304 const std::string& widthName,
0305 const int minEntriesForFit,
0306 const std::string& fitOption,
0307 const Acts::Logger& logger) {
0308 const int nBinsX = hist2d.GetNbinsX();
0309
0310
0311 auto meanHist = std::make_unique<TH1F>(
0312 meanName.c_str(), (std::string(hist2d.GetTitle()) + " mean").c_str(),
0313 nBinsX, hist2d.GetXaxis()->GetXmin(), hist2d.GetXaxis()->GetXmax());
0314 auto widthHist = std::make_unique<TH1F>(
0315 widthName.c_str(), (std::string(hist2d.GetTitle()) + " width").c_str(),
0316 nBinsX, hist2d.GetXaxis()->GetXmin(), hist2d.GetXaxis()->GetXmax());
0317
0318
0319 if (hist2d.GetXaxis()->GetXbins()->GetSize() > 0) {
0320 meanHist->SetBins(nBinsX, hist2d.GetXaxis()->GetXbins()->GetArray());
0321 widthHist->SetBins(nBinsX, hist2d.GetXaxis()->GetXbins()->GetArray());
0322 }
0323
0324
0325 int fitFailures = 0;
0326 for (int i = 1; i <= nBinsX; ++i) {
0327 const auto proj = std::unique_ptr<TH1D>(hist2d.ProjectionY(
0328 std::format("{}_projy_bin_{}", hist2d.GetName(), i).c_str(), i, i));
0329
0330 if (proj->GetEntries() < minEntriesForFit) {
0331 continue;
0332 }
0333
0334 const TFitResultPtr r = proj->Fit("gaus", fitOption.c_str());
0335 if ((r.Get() == nullptr) || ((r->Status() % 1000) != 0)) {
0336 ++fitFailures;
0337 ACTS_DEBUG("Failed to fit Gaussian for bin "
0338 << i << ": status "
0339 << (r.Get() != nullptr ? r->Status() : -1));
0340 continue;
0341 }
0342
0343
0344 meanHist->SetBinContent(i, r->Parameter(1));
0345 meanHist->SetBinError(i, r->ParError(1));
0346
0347
0348 widthHist->SetBinContent(i, r->Parameter(2));
0349 widthHist->SetBinError(i, r->ParError(2));
0350 }
0351 const double fitFailureFraction =
0352 (nBinsX > 0) ? static_cast<double>(fitFailures) / nBinsX : 0;
0353
0354 meanHist->GetXaxis()->SetTitle(hist2d.GetXaxis()->GetTitle());
0355 meanHist->GetYaxis()->SetTitle(hist2d.GetYaxis()->GetTitle());
0356
0357 widthHist->GetXaxis()->SetTitle(hist2d.GetXaxis()->GetTitle());
0358 widthHist->GetYaxis()->SetTitle(hist2d.GetYaxis()->GetTitle());
0359
0360 return {std::move(meanHist), std::move(widthHist), fitFailureFraction};
0361 }
0362
0363 std::tuple<std::unique_ptr<TH2F>, std::unique_ptr<TH2F>, double>
0364 ActsPlugins::extractMeanWidthProfiles(const TH3F& hist3d,
0365 const std::string& meanName,
0366 const std::string& widthName,
0367 const int minEntriesForFit,
0368 const std::string& fitOption,
0369 const Acts::Logger& logger) {
0370 const int nBinsX = hist3d.GetNbinsX();
0371 const int nBinsY = hist3d.GetNbinsY();
0372
0373
0374 auto meanHist = std::make_unique<TH2F>(
0375 meanName.c_str(), (std::string(hist3d.GetTitle()) + " mean").c_str(),
0376 nBinsX, hist3d.GetXaxis()->GetXmin(), hist3d.GetXaxis()->GetXmax(),
0377 nBinsY, hist3d.GetYaxis()->GetXmin(), hist3d.GetYaxis()->GetXmax());
0378
0379 auto widthHist = std::make_unique<TH2F>(
0380 widthName.c_str(), (std::string(hist3d.GetTitle()) + " width").c_str(),
0381 nBinsX, hist3d.GetXaxis()->GetXmin(), hist3d.GetXaxis()->GetXmax(),
0382 nBinsY, hist3d.GetYaxis()->GetXmin(), hist3d.GetYaxis()->GetXmax());
0383
0384
0385 if (hist3d.GetXaxis()->GetXbins()->GetSize() > 0 ||
0386 hist3d.GetYaxis()->GetXbins()->GetSize() > 0) {
0387 meanHist->SetBins(nBinsX, hist3d.GetXaxis()->GetXbins()->GetArray(), nBinsY,
0388 hist3d.GetYaxis()->GetXbins()->GetArray());
0389 widthHist->SetBins(nBinsX, hist3d.GetXaxis()->GetXbins()->GetArray(),
0390 nBinsY, hist3d.GetYaxis()->GetXbins()->GetArray());
0391 }
0392
0393
0394 int fitFailures = 0;
0395 for (int i = 1; i <= nBinsX; ++i) {
0396 for (int j = 1; j <= nBinsY; ++j) {
0397 const auto proj = std::unique_ptr<TH1D>(hist3d.ProjectionZ(
0398 std::format("{}_projz_bin_{}_{}", hist3d.GetName(), i, j).c_str(), i,
0399 i, j, j));
0400
0401 if (proj->GetEntries() < minEntriesForFit) {
0402 continue;
0403 }
0404
0405 const TFitResultPtr r = proj->Fit("gaus", fitOption.c_str());
0406 if ((r.Get() == nullptr) || ((r->Status() % 1000) != 0)) {
0407 ++fitFailures;
0408 ACTS_DEBUG("Failed to fit Gaussian for bin "
0409 << i << ", " << j << ": status "
0410 << (r.Get() != nullptr ? r->Status() : -1));
0411 continue;
0412 }
0413
0414
0415 meanHist->SetBinContent(i, j, r->Parameter(1));
0416 meanHist->SetBinError(i, j, r->ParError(1));
0417
0418
0419 widthHist->SetBinContent(i, j, r->Parameter(2));
0420 widthHist->SetBinError(i, j, r->ParError(2));
0421 }
0422 }
0423 const double fitFailureFraction =
0424 (nBinsX * nBinsY > 0)
0425 ? static_cast<double>(fitFailures) / (nBinsX * nBinsY)
0426 : 0;
0427
0428 meanHist->GetXaxis()->SetTitle(hist3d.GetXaxis()->GetTitle());
0429 meanHist->GetYaxis()->SetTitle(hist3d.GetYaxis()->GetTitle());
0430 meanHist->GetZaxis()->SetTitle(hist3d.GetZaxis()->GetTitle());
0431
0432 widthHist->GetXaxis()->SetTitle(hist3d.GetXaxis()->GetTitle());
0433 widthHist->GetYaxis()->SetTitle(hist3d.GetYaxis()->GetTitle());
0434 widthHist->GetZaxis()->SetTitle(hist3d.GetZaxis()->GetTitle());
0435
0436 return {std::move(meanHist), std::move(widthHist), fitFailureFraction};
0437 }