40{
41 if (!
object.
IsA()->InheritsFrom(
"TH1")) {
42 throw dqm_core::BadConfig(ERS_HERE, name, "does not inherit from TH1");
43 }
44 std::unique_ptr<TH1>
histogram(
static_cast<TH1 *
>(
object.Clone()));
46 throw dqm_core::BadConfig(ERS_HERE, name, "dimension > 2");
47 }
48 const bool isOneDimensional = (
histogram->GetDimension() == 1);
49
50
51
54 dqm_core::Result *
result =
new dqm_core::Result(dqm_core::Result::Undefined);
57 }
58
59
60
62 if (checkZeroContent && (
histogram->Integral() == 0) && (
histogram->GetEntries() > 0)) {
63 ERS_DEBUG(1,
"Histogram " <<
histogram->GetName() <<
" is filled with zeros!");
64 dqm_core::Result*
result =
new dqm_core::Result(dqm_core::Result::Red);
67 }
68
69
70
74
77 const bool dontCountSigmaOutliers = checkSigmaDev ?
static_cast<bool>(
tools::GetFirstFromMap(
"DontCountSigmaOutliers",
config.getParameters(), 0)) : false;
78
81
84
87
90
92
94
95
96 TH1 *refhist = 0;
97 if (diffRef || normRef) {
98 if (diffRef && normRef) {
99 throw dqm_core::BadConfig(ERS_HERE, name, "Can either divide or subtract reference, not both");
100 }
101 try {
102 refhist =
static_cast<TH1 *
>(
config.getReference());
103 } catch(dqm_core::Exception &ex) {
104 throw dqm_core::BadRefHist(ERS_HERE, name, "Could not retrieve reference");
105 }
106 if (
histogram->GetDimension() != refhist->GetDimension()) {
107 throw dqm_core::BadRefHist(ERS_HERE, name, "Wrong dimension of reference");
108 }
109 if ((
histogram->GetNbinsX() != refhist->GetNbinsX()) || (
histogram->GetNbinsY() != refhist->GetNbinsY())) {
110 throw dqm_core::BadRefHist(ERS_HERE, name, "Non-matching number of bins of reference");
111 }
112
113
114 refhist->Sumw2();
115 refhist->Scale(
histogram->Integral() / refhist->Integral());
116
117 if (diffRef)
histogram->Add(refhist, -1.0);
119 }
120
122 const int xminBin =
range[0];
123 const int xmaxBin =
range[1];
124 const int yminBin =
range[2];
125 const int ymaxBin =
range[3];
126
127 int zeroBins = 0;
128 for (
int i = xminBin;
i <= xmaxBin; ++
i) {
129 for (int j = yminBin; j <= ymaxBin; ++j) {
130 if (
histogram->GetBinContent(i, j) == 0) ++zeroBins;
131 }
132 }
133
134
135
136 int totalBadBins = 0;
137 int totalUncountedBadBins = 0;
139 double stddev = 0;
140 int currentIteration = 0;
141 const int maxIterations = 1000;
142
143 const int nBinsX =
histogram->GetNbinsX();
144 const int nBinsY =
histogram->GetNbinsY();
145 std::unique_ptr<TH1> knownOutliers(isOneDimensional ?
146 static_cast<TH1 *>(new TH1C("knownOutliers", "knownOutliers", nBinsX, 0, nBinsX)) :
147 static_cast<TH1 *>(new TH2C("knownOutliers", "knownOutliers", nBinsX, 0, nBinsX, nBinsY, 0, nBinsY)));
148
149 while (++currentIteration < maxIterations) {
150 int newBadBins = 0;
151 int newUncountedBadBins = 0;
152
153
156 double sumsqr = 0;
157 for (
int i = xminBin;
i <= xmaxBin; ++
i) {
158 for (int j = yminBin; j <= ymaxBin; ++j) {
159 const bool isOutlier = knownOutliers->GetBinContent(i, j);
160 if (isOutlier) continue;
161 const double binContent =
histogram->GetBinContent(i, j);
162 if ((binContent == 0) && ignore0) continue;
163
166 sumsqr += binContent * binContent;
167 }
168 }
170 stddev =
nBins ? std::sqrt(sumsqr / nBins -
mean *
mean) : 0;
171
172
173
174 if (checkRelDev || checkAbsDev || checkAbsLimit || checkSigmaDev) {
175 for (
int i = xminBin;
i <= xmaxBin; ++
i) {
176 for (int j = yminBin; j <= ymaxBin; ++j) {
177 const bool isOutlier = knownOutliers->GetBinContent(i, j);
178 if (isOutlier) continue;
179 const double binContent =
histogram->GetBinContent(i, j);
180 const double binError = subtractBinError ?
histogram->GetBinError(i, j) : 0.;
181 if ((binContent == 0) && ignore0) continue;
182
183 bool foundOutlier = false;
184 if (checkAbsLimit && !foundOutlier) {
185 if (binContent - binError > absLimit) {
186 ++newBadBins;
187 foundOutlier = true;
188 }
189 }
190 if (checkAbsDev && !foundOutlier) {
191 if (std::fabs(binContent -
mean) - binError > absDev) {
192 ++newBadBins;
193 foundOutlier = true;
194 }
195 }
196 if (checkRelDev && !foundOutlier) {
197 if (std::fabs(binContent -
mean) - binError > (relDev *
mean)) {
198 ++newBadBins;
199 foundOutlier = true;
200 }
201 }
202 if (checkSigmaDev && !foundOutlier) {
203 if (std::fabs(binContent -
mean) - binError > (sigmaDev * stddev)) {
204 if (dontCountSigmaOutliers) ++newUncountedBadBins;
205 else ++newBadBins;
206 foundOutlier = true;
207 }
208 }
209 if (foundOutlier) {
212 knownOutliers->SetBinContent(i, j, true);
213 }
214 }
215 }
216 }
217 if ((newBadBins == 0) && (newUncountedBadBins == 0)) break;
218 totalUncountedBadBins += newUncountedBadBins;
219 totalBadBins += newBadBins;
220 }
221 if (currentIteration == maxIterations) {
222 throw dqm_core::BadConfig(ERS_HERE, name, "maximum number of iterations reached while searching for outliers");
223 }
224 if (totalUncountedBadBins > 0) {
225 ERS_DEBUG(1,
"Histogram " <<
histogram->GetName() <<
" has " << totalUncountedBadBins <<
" bins exceeding sigma limit which are NOT counted as outliers, but which are omitted for calculating mean and stddev");
226 }
227
228
229 std::map<std::string, double>
results;
230 results[
"Number_of_outlier_bins"] = totalBadBins;
232 results[
"Corrected_standard_deviation"] = stddev;
233 results[
"Number_of_bins_equal_zero"] = zeroBins;
234
235
236 if (storeOutlierBins) {
237 int outlierIndex = 0;
238 for (
int i = xminBin;
i <= xmaxBin; ++
i) {
239 for (int j = yminBin; j <= ymaxBin; ++j) {
240 if (knownOutliers->GetBinContent(i, j)) {
241 outlierIndex++;
242 results[std::string(
"Outlier_bin_")+std::to_string(outlierIndex)] = knownOutliers->GetXaxis()->GetBinCenter(i);
243 }
244 }
245 }
246 }
247
248 if (checkFlatness) {
249 if (!isOneDimensional) {
250 throw dqm_core::BadConfig(ERS_HERE, name, "cannot check 2D histograms for flatness, please set CheckFlatness = 0");
251 }
252 std::unique_ptr<TF1> occupancyFit{};
253
254 const double xminAxis =
histogram->GetXaxis()->GetBinLowEdge(xminBin);
255 const double xmaxAxis =
histogram->GetXaxis()->GetBinUpEdge(xmaxBin);
256 const double width = (xmaxAxis - xminAxis);
257 const double center = (xmaxAxis + xminAxis) / 2;
258
259 if (fitCircular) {
260 occupancyFit = std::make_unique<TF1>("occupancyFit", "[0]+[1]*sin([3]*(x-[4]-[5]))+[2]*cos(2*[3]*(x-[4]-[5]))");
261 occupancyFit->SetParName(0, "constant");
262 occupancyFit->SetParName(1, "asym");
263 occupancyFit->SetParName(2, "sym");
264 occupancyFit->SetParName(3, "scale");
265 occupancyFit->SetParName(4, "offset");
266 occupancyFit->SetParName(5, "phaseoffset");
267 occupancyFit->SetParLimits(5, -0.5 *
width, +0.5 *
width);
268 occupancyFit->FixParameter(3, 2 *
M_PI /
width);
269 occupancyFit->FixParameter(4, center -
width / 2);
270 } else {
271 occupancyFit = std::make_unique<TF1>("occupancyFit", "[0]+[1]*(x-[3])+[2]*(x-[3])*(x-[3])");
272 occupancyFit->SetParName(0, "constant");
273 occupancyFit->SetParName(1, "asym");
274 occupancyFit->SetParName(2, "sym");
275 occupancyFit->SetParName(3, "offset");
276
277 occupancyFit->FixParameter(3, center);
278 }
279
280 occupancyFit->SetRange(xminAxis, xmaxAxis);
281 histogram->Fit(occupancyFit.get(),
"QNR");
282
283 double maxBin = 0;
284 double phaseOffset = 0;
285 if (fitCircular) {
286
287 phaseOffset = occupancyFit->GetParameter("phaseoffset");
288 maxBin = center +
width / 4 + phaseOffset;
289 } else {
290
291 maxBin = center +
width / 2;
292 }
293
294 const double constant = occupancyFit->GetParameter(
"constant");
295
296 double asym = 0;
297 double sym = 0;
298
299 if (diffRef) {
300 asym = occupancyFit->GetParameter("asym");
301 } else {
302 const double parBuff = occupancyFit->GetParameter("sym");
303 occupancyFit->SetParameter("sym", 0);
304 asym = std::fabs(occupancyFit->Eval(maxBin) - constant);
305 occupancyFit->SetParameter("sym", parBuff);
306 asym =
constant ? std::fabs(asym / constant) : 0;
307 }
308
309 if (diffRef) {
310 sym = occupancyFit->GetParameter("sym");
311 } else {
312 const double parBuff = occupancyFit->GetParameter("asym");
313 occupancyFit->SetParameter("asym", 0);
314 sym = std::fabs(occupancyFit->Eval(maxBin) - constant);
315 occupancyFit->SetParameter("asym", parBuff);
316 sym =
constant ? std::fabs(sym / constant) : 0;
317 if (!fitCircular) {
318 sym /= 2;
319 }
320 }
321
322 const int ndf = occupancyFit->GetNDF();
323 const double chisquare = occupancyFit->GetChisquare();
324 const double chisquareNDF = (
ndf > 0) ? (chisquare / ndf) : 0;
325
326
327 results[
"Max_rel_sym_deviation"] = sym;
328 results[
"Max_rel_asym_deviation"] = asym;
329 results[
"Chisquare_ndf"] = chisquareNDF;
330 results[
"Phase_offset"] = phaseOffset;
331
332 }
333
334
336}
void mean(std::vector< double > &bins, std::vector< double > &values, const std::vector< std::string > &files, const std::string &histname, const std::string &tplotname, const std::string &label="")
#define IsA
Declare the TObject style functions.