AnalysisTree
Loading...
Searching...
No Matches
HelperFunctions.hpp
1#ifndef ANALYSISTREE_INFRA_HELPER_FUNCTIONS_HPP
2#define ANALYSISTREE_INFRA_HELPER_FUNCTIONS_HPP
3
4#include "SimpleCut.hpp"
5
6#include <TFile.h>
7#include <TH1.h>
8
9#include <sstream>
10#include <string>
11#include <vector>
12
13namespace HelperFunctions {
14
15template<typename T>
16inline std::string ToStringWithPrecision(const T a_value, const int n) {
17 std::ostringstream out;
18 out.precision(n);
19 out << std::fixed << a_value;
20 return out.str();
21}
22
23template<typename T>
24inline std::string ToStringWithSignificantFigures(const T a_value, const int n) {
25 if (a_value == 0) return "0";
26
27 const double dMag = std::log10(std::abs(a_value));// scale of the a_value (e.g 1.* for 1.2345, 2.* for 12.345 etc)
28 const int iMag = static_cast<int>(dMag - n + 1 > 0 ? dMag - n + 1 : dMag - n);
29 const T shifted_value = a_value / std::pow(10, iMag); // shift decimal point to have all required digits to l.h.s. from it
30 const T rounded_value = static_cast<T>(std::round(shifted_value));// get rid of r.h.s. from decimal point
31 const T reshifted_value = rounded_value * std::pow(10, iMag); // return decimal point to its original place
32 const int precision = iMag < 0 ? -iMag : 0; // determine how many digits after decimal point one needs
33 return ToStringWithPrecision(reshifted_value, precision);
34}
35
36inline std::vector<AnalysisTree::SimpleCut> CreateRangeCuts(const std::vector<float>& ranges, const std::string& cutNamePrefix, const std::string& branchFieldName, bool isAppendWithOpenCut = false, int precision = -1) {
37 auto checkHasFractionalPart = [](float value) {
38 float fracPart = std::round(value) - value;
39 return std::abs(fracPart) > 1e-4;
40 };
41
42 auto countDigisAfterComma = [&](float value) {
43 int nDigis{0};
44 while (checkHasFractionalPart(value)) {
45 value *= 10;
46 ++nDigis;
47 }
48
49 return nDigis;
50 };
51
52 auto evaluateMaxDigisAfterComma = [&](const std::vector<float>& vec) {
53 int result = 0;
54 for (const auto& v : vec) {
55 result = std::max(result, countDigisAfterComma(v));
56 }
57
58 return result;
59 };
60
61 if (precision < 0) precision = evaluateMaxDigisAfterComma(ranges);
62
63 std::vector<AnalysisTree::SimpleCut> sliceCuts;
64 for (int iRange = 0; iRange < static_cast<int>(ranges.size()) - 1; iRange++) {
65 const std::string cutName = cutNamePrefix + ToStringWithPrecision(ranges.at(iRange), precision) + "_" + ToStringWithPrecision(ranges.at(iRange + 1), precision);
66 sliceCuts.emplace_back(AnalysisTree::RangeCut(branchFieldName, ranges.at(iRange), ranges.at(iRange + 1), cutName));
67 }
68
69 if (isAppendWithOpenCut) sliceCuts.emplace_back(AnalysisTree::OpenCut(branchFieldName.substr(0, branchFieldName.find('.'))));
70
71 return sliceCuts;
72}
73
74inline std::vector<AnalysisTree::SimpleCut> CreateEqualCuts(const std::vector<int>& values, const std::string& cutNamePrefix, const std::string& branchFieldName) {
75 std::vector<AnalysisTree::SimpleCut> sliceCuts;
76 for (const auto& value : values) {
77 const std::string cutName = cutNamePrefix + std::to_string(value);
78 sliceCuts.emplace_back(AnalysisTree::EqualsCut(branchFieldName, value, cutName));
79 }
80
81 return sliceCuts;
82}
83
84inline bool StringToBool(const std::string& str) {
85 if (str == "true") return true;
86 else if (str == "false")
87 return false;
88 else
89 throw std::runtime_error("HelperFunctions::StringToBool(): argument must be either true or false");
90}
91
92template<typename T>
93inline std::vector<T> MergeVectors(const std::vector<T>& vec1, const std::vector<T>& vec2) {
94 std::vector<T> result;
95 result.reserve(vec1.size() + vec2.size());
96 result.insert(result.end(), vec1.begin(), vec1.end());
97 result.insert(result.end(), vec2.begin(), vec2.end());
98
99 return result;
100}
101
102template<typename T, typename... Args>
103inline std::vector<T> MergeVectors(const std::vector<T>& vec1, const std::vector<T>& vec2, const Args&... args) {
104 return MergeVectors(vec1, MergeVectors(vec2, args...));
105}
106
107inline TFile* OpenFileWithNullptrCheck(const std::string& fileName, const std::string& option = "read") {
108 TFile* file = TFile::Open(fileName.c_str(), option.c_str());
109 if (file == nullptr) {
110 throw std::runtime_error("HelperFunctions::OpenFileWithNullptrCheck() - file " + fileName + " is missing");
111 }
112 return file;
113}
114
115template<typename T>
116inline T* GetObjectWithNullptrCheck(TFile* fileIn, const std::string& objectName) {
117 T* ptr = fileIn->Get<T>(objectName.c_str());
118 if (ptr == nullptr) {
119 throw std::runtime_error("HelperFunctions::GetObjectWithNullptrCheck() - object " + objectName + " in file " + fileIn->GetName() + " is missing");
120 }
121 return ptr;
122}
123
124inline void CheckHistogramsForXaxisIdentity(const TH1* h1, const TH1* h2) {
125 if (h1->GetNbinsX() != h2->GetNbinsX()) {
126 throw std::runtime_error("HelperFunctions::CheckHistogramsForXaxisIdentity(): nBinsX do not match for " + static_cast<std::string>(h1->GetName()) + " and " + h2->GetName());
127 }
128 const int nBins = h1->GetNbinsX();
129 for (int iBin = 1; iBin <= nBins; iBin++) {
130 if (std::abs(h1->GetBinCenter(iBin) - h2->GetBinCenter(iBin)) > 1e-6) {
131 throw std::runtime_error("HelperFunctions::CheckHistogramsForXaxisIdentity(): bins do not coincide for " + static_cast<std::string>(h1->GetName()) + " and " + h2->GetName());
132 }
133 }
134}
135
136inline void Sumw2IfNotYet(TH1* histo, bool value = true) {
137 const bool isSumw2Already = histo->GetSumw2N() > 0;
138 if (isSumw2Already != value) histo->Sumw2(value);
139}
140
141inline TH1* MergeHistograms(const std::vector<TH1*>& histos) {
142 bool isSumw2{false};
143 for(const auto& h : histos) {
144 CheckHistogramsForXaxisIdentity(h, histos.at(0));
145 isSumw2 |= h->GetSumw2N() > 0;
146 }
147
148 TH1* hResult = dynamic_cast<TH1*>(histos.at(0)->Clone("hMerged"));
149 Sumw2IfNotYet(hResult);
150 hResult->SetDirectory(nullptr);
151 for(size_t iH = 1, nHs = histos.size(); iH < nHs; ++iH) {
152 hResult->Add(histos.at(iH));
153 }
154 Sumw2IfNotYet(hResult, isSumw2);
155
156 return hResult;
157}
158
159inline TH1* MergeHistograms(TFile* fileIn, const std::vector<std::string>& histoNames) {
160 std::vector<TH1*> histos;
161 for (const auto& hN : histoNames) {
162 histos.emplace_back(GetObjectWithNullptrCheck<TH1>(fileIn, hN));
163 }
164 TH1* hResult = MergeHistograms(histos);
165
166 return hResult;
167}
168
169template<typename T>
170inline TDirectory* MkDirIfNotExists(T* fileOrDirectory, const std::string& name) {
171 if (fileOrDirectory == nullptr) throw std::runtime_error("HelperFunctions::MkDirIfNotExists(): file or directory ptr is null");
172 TDirectory* result = fileOrDirectory->GetDirectory(name.c_str());
173 if (result == nullptr) fileOrDirectory->mkdir(name.c_str());
174 result = fileOrDirectory->GetDirectory(name.c_str());
175 return result;
176}
177
178template<typename T>
179inline void CD(T* fileOrDirectory, const std::string& name) {
180 auto destination = MkDirIfNotExists(fileOrDirectory, name);
181 destination->cd();
182}
183
184inline double InterpolateTH1SuppressWarning(const TH1* h, double value) {
185 double result;
186 if (value <= h->GetBinLowEdge(1) || value >= h->GetBinLowEdge(h->GetNbinsX() + 1)) result = 0.;
187 else
188 result = h->Interpolate(value);
189 return result;
190}
191
192}// namespace HelperFunctions
193#endif// ANALYSISTREE_INFRA_HELPER_FUNCTIONS_HPP
SimpleCut EqualsCut(const std::string &variable_name, int value, const std::string &title)
Definition SimpleCut.cpp:34
SimpleCut RangeCut(const std::string &variable_name, double lo, double hi, const std::string &title)
Definition SimpleCut.cpp:30
SimpleCut OpenCut(const std::string &branchName)
Definition SimpleCut.cpp:46