41 if (!
object.
IsA()->InheritsFrom(
"TH1")) {
42 throw dqm_core::BadConfig(ERS_HERE,
name,
"does not inherit from TH1");
44 std::unique_ptr<TH1>
histogram(
static_cast<TH1 *
>(
object.Clone()));
46 throw dqm_core::BadConfig(ERS_HERE,
name,
"dimension > 2");
48 const bool isOneDimensional = (
histogram->GetDimension() == 1);
62 if (checkZeroContent && (
histogram->Integral() == 0) && (
histogram->GetEntries() > 0)) {
63 ERS_DEBUG(1,
"Histogram " <<
histogram->GetName() <<
" is filled with zeros!");
77 const bool dontCountSigmaOutliers = checkSigmaDev ?
static_cast<bool>(
tools::GetFirstFromMap(
"DontCountSigmaOutliers",
config.getParameters(), 0)) :
false;
97 if (diffRef || normRef) {
98 if (diffRef && normRef) {
99 throw dqm_core::BadConfig(ERS_HERE,
name,
"Can either divide or subtract reference, not both");
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");
106 if (
histogram->GetDimension() != refhist->GetDimension()) {
107 throw dqm_core::BadRefHist(ERS_HERE,
name,
"Wrong dimension of reference");
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");
115 refhist->Scale(
histogram->Integral() / refhist->Integral());
117 if (diffRef)
histogram->Add(refhist, -1.0);
122 const int xminBin =
range[0];
123 const int xmaxBin =
range[1];
124 const int yminBin =
range[2];
125 const int ymaxBin =
range[3];
128 for (
int i = xminBin;
i <= xmaxBin; ++
i) {
129 for (
int j = yminBin; j <= ymaxBin; ++j) {
130 if (
histogram->GetBinContent(
i, j) == 0) ++zeroBins;
136 int totalBadBins = 0;
137 int totalUncountedBadBins = 0;
140 int currentIteration = 0;
141 const int maxIterations = 1000;
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)));
149 while (++currentIteration < maxIterations) {
151 int newUncountedBadBins = 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;
166 sumsqr += binContent * binContent;
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;
183 bool foundOutlier =
false;
184 if (checkAbsLimit && !foundOutlier) {
185 if (binContent - binError > absLimit) {
190 if (checkAbsDev && !foundOutlier) {
191 if (std::fabs(binContent -
mean) - binError > absDev) {
196 if (checkRelDev && !foundOutlier) {
197 if (std::fabs(binContent -
mean) - binError > (relDev *
mean)) {
202 if (checkSigmaDev && !foundOutlier) {
203 if (std::fabs(binContent -
mean) - binError > (sigmaDev * stddev)) {
204 if (dontCountSigmaOutliers) ++newUncountedBadBins;
212 knownOutliers->SetBinContent(
i, j,
true);
217 if ((newBadBins == 0) && (newUncountedBadBins == 0))
break;
218 totalUncountedBadBins += newUncountedBadBins;
219 totalBadBins += newBadBins;
221 if (currentIteration == maxIterations) {
222 throw dqm_core::BadConfig(ERS_HERE,
name,
"maximum number of iterations reached while searching for outliers");
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");
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;
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)) {
242 results[std::string(
"Outlier_bin_")+
std::to_string(outlierIndex)] = knownOutliers->GetXaxis()->GetBinCenter(
i);
249 if (!isOneDimensional) {
250 throw dqm_core::BadConfig(ERS_HERE,
name,
"cannot check 2D histograms for flatness, please set CheckFlatness = 0");
252 std::unique_ptr<TF1> occupancyFit{};
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;
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);
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");
277 occupancyFit->FixParameter(3, center);
280 occupancyFit->SetRange(xminAxis, xmaxAxis);
281 histogram->Fit(occupancyFit.get(),
"QNR");
284 double phaseOffset = 0;
287 phaseOffset = occupancyFit->GetParameter(
"phaseoffset");
288 maxBin = center +
width / 4 + phaseOffset;
291 maxBin = center +
width / 2;
294 const double constant = occupancyFit->GetParameter(
"constant");
300 asym = occupancyFit->GetParameter(
"asym");
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);
310 sym = occupancyFit->GetParameter(
"sym");
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);
322 const int ndf = occupancyFit->GetNDF();
323 const double chisquare = occupancyFit->GetChisquare();
324 const double chisquareNDF = (
ndf > 0) ? (chisquare /
ndf) : 0;
327 results[
"Max_rel_sym_deviation"] = sym;
328 results[
"Max_rel_asym_deviation"] = asym;
329 results[
"Chisquare_ndf"] = chisquareNDF;
330 results[
"Phase_offset"] = phaseOffset;