/
githubmirror
/
cmssw
Обзор
Документация
Войти
/
githubmirror
/
cmssw
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
DQMServices/Core/src/QTest.cc
1 403 строки
47 KB
Shahzad Malik Muzaffar
[DQM] Changes suggested by new llvm18 clang-format
05 сен 2024, 17:08
05 сен 2024, 17:08
3bee7b8
Код
Авторство
О чём код?
#include "DQMServices/Core/interface/QTest.h" #include "DQMServices/Core/interface/DQMStore.h" #include "Math/ProbFuncMathCore.h" #include "TMath.h" #include <cmath> #include <iostream> #include <sstream> using namespace std; const float QCriterion::ERROR_PROB_THRESHOLD = 0.50; const float QCriterion::WARNING_PROB_THRESHOLD = 0.90; // initialize values void QCriterion::init() { errorProb_ = ERROR_PROB_THRESHOLD; warningProb_ = WARNING_PROB_THRESHOLD; setAlgoName("NO_ALGORITHM"); status_ = dqm::qstatus::DID_NOT_RUN; message_ = "NO_MESSAGE"; verbose_ = 0; // 0 = silent, 1 = algorithmic failures, 2 = info } float QCriterion::runTest(const MonitorElement* /* me */) { return 0.; } //===================================================// //================ QUALITY TESTS ====================// //==================================================// //----------------------------------------------------// //--------------- ContentsXRange ---------------------// //----------------------------------------------------// float ContentsXRange::runTest(const MonitorElement* me) { badChannels_.clear(); if (!me) return -1; if (!me->getRootObject()) return -1; TH1* h = nullptr; if (verbose_ > 1) std::cout << "QTest:" << getAlgoName() << "::runTest called on " << me->getFullname() << "\n"; // -- TH1F if (me->kind() == MonitorElement::Kind::TH1F) { h = me->getTH1F(); } // -- TH1S else if (me->kind() == MonitorElement::Kind::TH1S) { h = me->getTH1S(); } // -- TH1D else if (me->kind() == MonitorElement::Kind::TH1D) { h = me->getTH1D(); } else { if (verbose_ > 0) std::cout << "QTest:ContentsXRange" << " ME " << me->getFullname() << " does not contain TH1F/TH1S/TH1D, exiting\n"; return -1; } if (!rangeInitialized_) { if (h->GetXaxis()) setAllowedXRange(h->GetXaxis()->GetXmin(), h->GetXaxis()->GetXmax()); else return -1; } int ncx = h->GetXaxis()->GetNbins(); // use underflow bin int first = 0; // 1 // use overflow bin int last = ncx + 1; // ncx // all entries double sum = 0; // entries outside X-range double fail = 0; int bin; for (bin = first; bin <= last; ++bin) { double contents = h->GetBinContent(bin); double x = h->GetBinCenter(bin); sum += contents; if (x < xmin_ || x > xmax_) fail += contents; } if (sum == 0) return 1; // return fraction of entries within allowed X-range return (sum - fail) / sum; } //-----------------------------------------------------// //--------------- ContentsYRange ---------------------// //----------------------------------------------------// float ContentsYRange::runTest(const MonitorElement* me) { badChannels_.clear(); if (!me) return -1; if (!me->getRootObject()) return -1; TH1* h = nullptr; if (verbose_ > 1) std::cout << "QTest:" << getAlgoName() << "::runTest called on " << me->getFullname() << "\n"; if (me->kind() == MonitorElement::Kind::TH1F) { h = me->getTH1F(); //access Test histo } else if (me->kind() == MonitorElement::Kind::TH1S) { h = me->getTH1S(); //access Test histo } else if (me->kind() == MonitorElement::Kind::TH1D) { h = me->getTH1D(); //access Test histo } else { if (verbose_ > 0) std::cout << "QTest:ContentsYRange" << " ME " << me->getFullname() << " does not contain TH1F/TH1S/TH1D, exiting\n"; return -1; } if (!rangeInitialized_ || !h->GetXaxis()) return 1; // all bins are accepted if no initialization int ncx = h->GetXaxis()->GetNbins(); // do NOT use underflow bin int first = 1; // do NOT use overflow bin int last = ncx; // bins outside Y-range int fail = 0; int bin; if (useEmptyBins_) ///Standard test ! { for (bin = first; bin <= last; ++bin) { double contents = h->GetBinContent(bin); bool failure = false; failure = (contents < ymin_ || contents > ymax_); // allowed y-range: [ymin_, ymax_] if (failure) { DQMChannel chan(bin, 0, 0, contents, h->GetBinError(bin)); badChannels_.push_back(chan); ++fail; } } // return fraction of bins that passed test return 1. * (ncx - fail) / ncx; } else ///AS quality test !!! { for (bin = first; bin <= last; ++bin) { double contents = h->GetBinContent(bin); bool failure = false; if (contents) failure = (contents < ymin_ || contents > ymax_); // allowed y-range: [ymin_, ymax_] if (failure) ++fail; } // return fraction of bins that passed test return 1. * (ncx - fail) / ncx; } ///end of AS quality tests } //-----------------------------------------------------// //------------------ DeadChannel ---------------------// //----------------------------------------------------// float DeadChannel::runTest(const MonitorElement* me) { badChannels_.clear(); if (!me) return -1; if (!me->getRootObject()) return -1; TH1* h1 = nullptr; TH2* h2 = nullptr; //initialize histogram pointers if (verbose_ > 1) std::cout << "QTest:" << getAlgoName() << "::runTest called on " << me->getFullname() << "\n"; //TH1F if (me->kind() == MonitorElement::Kind::TH1F) { h1 = me->getTH1F(); //access Test histo } //TH1S else if (me->kind() == MonitorElement::Kind::TH1S) { h1 = me->getTH1S(); //access Test histo } //TH1D else if (me->kind() == MonitorElement::Kind::TH1D) { h1 = me->getTH1D(); //access Test histo } //-- TH2F else if (me->kind() == MonitorElement::Kind::TH2F) { h2 = me->getTH2F(); // access Test histo } //-- TH2S else if (me->kind() == MonitorElement::Kind::TH2S) { h2 = me->getTH2S(); // access Test histo } //-- TH2D else if (me->kind() == MonitorElement::Kind::TH2D) { h2 = me->getTH2D(); // access Test histo } else { if (verbose_ > 0) std::cout << "QTest:DeadChannel" << " ME " << me->getFullname() << " does not contain TH1F/TH1S/TH1D/TH2F/TH2S/TH2D, exiting\n"; return -1; } int fail = 0; // number of failed channels //--------- do the quality test for 1D histo ---------------// if (h1 != nullptr) { if (!rangeInitialized_ || !h1->GetXaxis()) return 1; // all bins are accepted if no initialization int ncx = h1->GetXaxis()->GetNbins(); int first = 1; int last = ncx; int bin; /// loop over all channels for (bin = first; bin <= last; ++bin) { double contents = h1->GetBinContent(bin); bool failure = false; failure = contents <= ymin_; // dead channel: equal to or less than ymin_ if (failure) { DQMChannel chan(bin, 0, 0, contents, h1->GetBinError(bin)); badChannels_.push_back(chan); ++fail; } } //return fraction of alive channels return 1. * (ncx - fail) / ncx; } //----------------------------------------------------------// //--------- do the quality test for 2D -------------------// else if (h2 != nullptr) { int ncx = h2->GetXaxis()->GetNbins(); // get X bins int ncy = h2->GetYaxis()->GetNbins(); // get Y bins /// loop over all bins for (int cx = 1; cx <= ncx; ++cx) { for (int cy = 1; cy <= ncy; ++cy) { double contents = h2->GetBinContent(h2->GetBin(cx, cy)); bool failure = false; failure = contents <= ymin_; // dead channel: equal to or less than ymin_ if (failure) { DQMChannel chan(cx, cy, 0, contents, h2->GetBinError(h2->GetBin(cx, cy))); badChannels_.push_back(chan); ++fail; } } } //return fraction of alive channels return 1. * (ncx * ncy - fail) / (ncx * ncy); } else { if (verbose_ > 0) std::cout << "QTest:DeadChannel" << " TH1/TH2F are NULL, exiting\n"; return -1; } } //-----------------------------------------------------// //---------------- NoisyChannel ---------------------// //----------------------------------------------------// // run the test (result: fraction of channels not appearing noisy or "hot") // [0, 1] or <0 for failure float NoisyChannel::runTest(const MonitorElement* me) { badChannels_.clear(); if (!me) return -1; if (!me->getRootObject()) return -1; TH1* h = nullptr; //initialize histogram pointer TH2* h2 = nullptr; //initialize histogram pointer if (verbose_ > 1) std::cout << "QTest:" << getAlgoName() << "::runTest called on " << me->getFullname() << "\n"; int nbins = 0; int nbinsX = 0, nbinsY = 0; //-- TH1F if (me->kind() == MonitorElement::Kind::TH1F) { nbins = me->getTH1F()->GetXaxis()->GetNbins(); h = me->getTH1F(); // access Test histo } //-- TH1S else if (me->kind() == MonitorElement::Kind::TH1S) { nbins = me->getTH1S()->GetXaxis()->GetNbins(); h = me->getTH1S(); // access Test histo } //-- TH1D else if (me->kind() == MonitorElement::Kind::TH1D) { nbins = me->getTH1D()->GetXaxis()->GetNbins(); h = me->getTH1D(); // access Test histo } //-- TH2 else if (me->kind() == MonitorElement::Kind::TH2F) { nbinsX = me->getTH2F()->GetXaxis()->GetNbins(); nbinsY = me->getTH2F()->GetYaxis()->GetNbins(); h2 = me->getTH2F(); // access Test histo } //-- TH2 else if (me->kind() == MonitorElement::Kind::TH2S) { nbinsX = me->getTH2S()->GetXaxis()->GetNbins(); nbinsY = me->getTH2S()->GetYaxis()->GetNbins(); h2 = me->getTH2S(); // access Test histo } //-- TH2 else if (me->kind() == MonitorElement::Kind::TH2D) { nbinsX = me->getTH2F()->GetXaxis()->GetNbins(); nbinsY = me->getTH2F()->GetYaxis()->GetNbins(); h2 = me->getTH2D(); // access Test histo } else { if (verbose_ > 0) std::cout << "QTest:NoisyChannel" << " ME " << me->getFullname() << " does not contain TH1F/TH1S/TH1D or TH2F/TH2S/TH2D, exiting\n"; return -1; } //-- QUALITY TEST itself // do NOT use underflow bin int first = 1; // do NOT use overflow bin int last = nbins; int lastX = nbinsX, lastY = nbinsY; // bins outside Y-range int fail = 0; int bin; int binX, binY; if (h != nullptr) { if (!rangeInitialized_ || !h->GetXaxis()) { return 1; // all channels are accepted if tolerance has not been set } for (bin = first; bin <= last; ++bin) { double contents = h->GetBinContent(bin); double average = getAverage(bin, h); bool failure = false; if (average != 0) failure = (((contents - average) / std::abs(average)) > tolerance_); if (failure) { ++fail; DQMChannel chan(bin, 0, 0, contents, h->GetBinError(bin)); badChannels_.push_back(chan); } } // return fraction of bins that passed test return 1. * (nbins - fail) / nbins; } else if (h2 != nullptr) { for (binY = first; binY <= lastY; ++binY) { for (binX = first; binX <= lastX; ++binX) { double contents = h2->GetBinContent(binX, binY); double average = getAverage2D(binX, binY, h2); bool failure = false; if (average != 0) failure = (((contents - average) / std::abs(average)) > tolerance_); if (failure) { ++fail; DQMChannel chan(binX, 0, 0, contents, h2->GetBinError(binX)); badChannels_.push_back(chan); } } //end x loop } //end y loop // return fraction of bins that passed test return 1. * ((nbinsX * nbinsY) - fail) / (nbinsX * nbinsY); } //end nullptr conditional else { if (verbose_ > 0) std::cout << "QTest:NoisyChannel" << " TH1/TH2F are NULL, exiting\n"; return -1; } } // get average for bin under consideration // (see description of method setNumNeighbors) double NoisyChannel::getAverage(int bin, const TH1* h) const { int first = 1; // Do NOT use underflow bin int ncx = h->GetXaxis()->GetNbins(); // Do NOT use overflow bin double sum = 0; int bin_start, bin_end; int add_right = 0; int add_left = 0; bin_start = bin - numNeighbors_; // First bin in integral bin_end = bin + numNeighbors_; // Last bin in integral if (bin_start < first) { // If neighbors take you outside of histogram range shift integral right add_right = first - bin_start; // How much to shift remembering we are not using underflow bin_start = first; // Remember to reset the starting bin bin_end += add_right; if (bin_end > ncx) bin_end = ncx; // If the test would be larger than histogram just sum histogram without overflow } if (bin_end > ncx) { // Now we make sure doesn't run off right edge of histogram add_left = bin_end - ncx; bin_end = ncx; bin_start -= add_left; if (bin_start < first) bin_start = first; // If the test would be larger than histogram just sum histogram without underflow } sum += h->Integral(bin_start, bin_end); sum -= h->GetBinContent(bin); int dimension = 2 * numNeighbors_ + 1; if (dimension > h->GetNbinsX()) dimension = h->GetNbinsX(); return sum / (dimension - 1); } double NoisyChannel::getAverage2D(int binX, int binY, const TH2* h2) const { /// Do NOT use underflow or overflow bins int firstX = 1; int firstY = 1; double sum = 0; int ncx = h2->GetXaxis()->GetNbins(); int ncy = h2->GetYaxis()->GetNbins(); int neighborsX, neighborsY; // Convert unsigned input to int so we can use comparators neighborsX = numNeighbors_; neighborsY = numNeighbors_; int bin_startX, bin_endX; int add_rightX = 0; // Start shifts at 0 int add_leftX = 0; int bin_startY, bin_endY; int add_topY = 0; int add_downY = 0; bin_startX = binX - neighborsX; // First bin in X bin_endX = binX + neighborsX; // Last bin in X if (bin_startX < firstX) { // If neighbors take you outside of histogram range shift integral right add_rightX = firstX - bin_startX; // How much to shift remembering we are no using underflow bin_startX = firstX; // Remember to reset the starting bin bin_endX += add_rightX; if (bin_endX > ncx) bin_endX = ncx; } if (bin_endX > ncx) { // Now we make sure doesn't run off right edge of histogram add_leftX = bin_endX - ncx; bin_endX = ncx; bin_startX -= add_leftX; if (bin_startX < firstX) bin_startX = firstX; // If the test would be larger than histogram just sum histogram without underflow } bin_startY = binY - neighborsY; // First bin in Y bin_endY = binY + neighborsY; // Last bin in Y if (bin_startY < firstY) { // If neighbors take you outside of histogram range shift integral up add_topY = firstY - bin_startY; // How much to shift remembering we are no using underflow bin_startY = firstY; // Remember to reset the starting bin bin_endY += add_topY; if (bin_endY > ncy) bin_endY = ncy; } if (bin_endY > ncy) { // Now we make sure doesn't run off top edge of histogram add_downY = bin_endY - ncy; bin_endY = ncy; bin_startY -= add_downY; if (bin_startY < firstY) bin_startY = firstY; // If the test would be larger than histogram just sum histogram without underflow } sum += h2->Integral(bin_startX, bin_endX, bin_startY, bin_endY); sum -= h2->GetBinContent(binX, binY); int dimensionX = 2 * neighborsX + 1; int dimensionY = 2 * neighborsY + 1; if (dimensionX > h2->GetNbinsX()) dimensionX = h2->GetNbinsX(); if (dimensionY > h2->GetNbinsY()) dimensionY = h2->GetNbinsY(); return sum / (dimensionX * dimensionY - 1); // Average is sum over the # of bins used } // End getAverage2D //-----------------------------------------------------// //-----Content Sigma (Emma Yeager and Chad Freer)------// //----------------------------------------------------// // run the test (result: fraction of channels with sigma that is not noisy or hot) float ContentSigma::runTest(const MonitorElement* me) { badChannels_.clear(); if (!me) return -1; if (!me->getRootObject()) return -1; TH1* h = nullptr; //initialize histogram pointer if (verbose_ > 1) std::cout << "QTest:" << getAlgoName() << "::runTest called on " << me->getFullname() << "\n"; unsigned nbinsX; unsigned nbinsY; //-- TH1F if (me->kind() == MonitorElement::Kind::TH1F) { nbinsX = me->getTH1F()->GetXaxis()->GetNbins(); nbinsY = me->getTH1F()->GetYaxis()->GetNbins(); h = me->getTH1F(); // access Test histo } //-- TH1S else if (me->kind() == MonitorElement::Kind::TH1S) { nbinsX = me->getTH1S()->GetXaxis()->GetNbins(); nbinsY = me->getTH1S()->GetYaxis()->GetNbins(); h = me->getTH1S(); // access Test histo } //-- TH1D else if (me->kind() == MonitorElement::Kind::TH1D) { nbinsX = me->getTH1D()->GetXaxis()->GetNbins(); nbinsY = me->getTH1D()->GetYaxis()->GetNbins(); h = me->getTH1D(); // access Test histo } //-- TH2 else if (me->kind() == MonitorElement::Kind::TH2F) { nbinsX = me->getTH2F()->GetXaxis()->GetNbins(); nbinsY = me->getTH2F()->GetYaxis()->GetNbins(); h = me->getTH2F(); // access Test histo } //-- TH2 else if (me->kind() == MonitorElement::Kind::TH2S) { nbinsX = me->getTH2S()->GetXaxis()->GetNbins(); nbinsY = me->getTH2S()->GetYaxis()->GetNbins(); h = me->getTH2S(); // access Test histo } //-- TH2 else if (me->kind() == MonitorElement::Kind::TH2D) { nbinsX = me->getTH2D()->GetXaxis()->GetNbins(); nbinsY = me->getTH2D()->GetYaxis()->GetNbins(); h = me->getTH2D(); // access Test histo } else { if (verbose_ > 0) std::cout << "QTest:ContentSigma" << " ME " << me->getFullname() << " does not contain TH1F/TH1S/TH1D or TH2F/TH2S/TH2D, exiting\n"; return -1; } //-- QUALITY TEST itself if (!rangeInitialized_ || !h->GetXaxis()) return 1; // all channels are accepted if tolerance has not been set int fail = 0; // initialize bin failure count unsigned xMin = 1; //initialize minimums and maximums with expected values unsigned yMin = 1; unsigned xMax = nbinsX; unsigned yMax = nbinsY; unsigned XBlocks = numXblocks_; //Initialize xml inputs blocks and neighbors unsigned YBlocks = numYblocks_; unsigned neighborsX = numNeighborsX_; unsigned neighborsY = numNeighborsY_; unsigned Xbinnum = 1; unsigned Ybinnum = 1; unsigned XWidth = 0; unsigned YWidth = 0; if (neighborsX == 999) { neighborsX = 0; } if (neighborsY == 999) { neighborsY = 0; } //give users option for automatic mininum and maximum selection by inputting 0 to any of the parameters // check that user's parameters are completely in agreement with histogram // for instance, if inputted xMax is out of range xMin will automatically be ignored if (xMin_ != 0 && xMax_ != 0) { if ((xMax_ <= nbinsX) && (xMin_ <= xMax_)) { // rescale area of histogram being analyzed nbinsX = xMax_ - xMin_ + 1; xMax = xMax_; // do NOT use overflow bin xMin = xMin_; // do NOT use underflow bin } } //give users option for automatic mininum and maximum selection by inputting 0 to any of the parameters if (yMin_ != 0 && yMax_ != 0) { if ((yMax_ <= nbinsY) && (yMin_ <= yMax_)) { nbinsY = yMax_ - yMin_ + 1; yMax = yMax_; yMin = yMin_; } } if (neighborsX * 2 >= nbinsX) { //make sure neighbor check does not overlap with bin under consideration if (nbinsX % 2 == 0) { neighborsX = nbinsX / 2 - 1; //set neighbors for no overlap } else { neighborsX = (nbinsX - 1) / 2; } } if (neighborsY * 2 >= nbinsY) { if (nbinsY % 2 == 0) { neighborsY = nbinsY / 2 - 1; } else { neighborsY = (nbinsY - 1) / 2; } } if (XBlocks == 999) { //Setting 999 prevents blocks and does quality tests by bins only XBlocks = nbinsX; } if (YBlocks == 999) { YBlocks = nbinsY; } Xbinnum = nbinsX / XBlocks; Ybinnum = nbinsY / YBlocks; for (unsigned groupx = 0; groupx < XBlocks; ++groupx) { //Test over all the blocks for (unsigned groupy = 0; groupy < YBlocks; ++groupy) { double blocksum = 0; for (unsigned binx = 0; binx < Xbinnum; ++binx) { //Sum the contents of the block in question for (unsigned biny = 0; biny < Ybinnum; ++biny) { if (groupx * Xbinnum + xMin + binx <= xMax && groupy * Ybinnum + yMin + biny <= yMax) { blocksum += abs(h->GetBinContent(groupx * Xbinnum + xMin + binx, groupy * Ybinnum + yMin + biny)); } } } double sum = getNeighborSum(groupx, groupy, XBlocks, YBlocks, neighborsX, neighborsY, h); sum -= blocksum; //remove center block to test if (neighborsX > groupx) { //Find correct average at the edges XWidth = neighborsX + groupx + 1; } else if (neighborsX > (XBlocks - (groupx + 1))) { XWidth = (XBlocks - groupx) + neighborsX; } else { XWidth = 2 * neighborsX + 1; } if (neighborsY > groupy) { YWidth = neighborsY + groupy + 1; } else if (neighborsY > (YBlocks - (groupy + 1))) { YWidth = (YBlocks - groupy) + neighborsY; } else { YWidth = 2 * neighborsY + 1; } double average = sum / (XWidth * YWidth - 1); double sigma = getNeighborSigma(average, groupx, groupy, XBlocks, YBlocks, neighborsX, neighborsY, h); //get rid of block being tested just like we did with the average sigma -= (average - blocksum) * (average - blocksum); double sigma_2 = sqrt(sigma) / sqrt(XWidth * YWidth - 2); //N-1 where N=XWidth*YWidth - 1 double sigma_real = sigma_2 / (XWidth * YWidth - 1); //double avg_uncrt = average*sqrt(sum)/sum;//Obsolete now(Chad Freer) double avg_uncrt = 3 * sigma_real; double probNoisy = ROOT::Math::poisson_cdf_c(blocksum - 1, average + avg_uncrt); double probDead = ROOT::Math::poisson_cdf(blocksum, average - avg_uncrt); double thresholdNoisy = ROOT::Math::normal_cdf_c(toleranceNoisy_); double thresholdDead = ROOT::Math::normal_cdf(-1 * toleranceDead_); int failureNoisy = 0; int failureDead = 0; if (average != 0) { if (noisy_ && dead_) { if (blocksum > average) { failureNoisy = probNoisy < thresholdNoisy; } else { failureDead = probDead < thresholdDead; } } else if (noisy_) { if (blocksum > average) { failureNoisy = probNoisy < thresholdNoisy; } } else if (dead_) { if (blocksum < average) { failureDead = probDead < thresholdDead; } } else { std::cout << "No test type selected!\n"; } //Following lines useful for debugging using verbose (Chad Freer) //string histName = h->GetName(); //if (histName == "emtfTrackBX") { // std::printf("Chad says: %i XBlocks, %i XBlocks, %f Blocksum, %f Average", XBlocks,YBlocks,blocksum,average);} } if (failureNoisy || failureDead) { ++fail; //DQMChannel chan(groupx*Xbinnum+xMin+binx, 0, 0, blocksum, h->GetBinError(groupx*Xbinnum+xMin+binx)); //badChannels_.push_back(chan); } } } return 1. * ((XBlocks * YBlocks) - fail) / (XBlocks * YBlocks); } //Gets the sum of the bins surrounding the block to be tested (Chad Freer) double ContentSigma::getNeighborSum(unsigned groupx, unsigned groupy, unsigned Xblocks, unsigned Yblocks, unsigned neighborsX, unsigned neighborsY, const TH1* h) const { double sum = 0; unsigned nbinsX = h->GetXaxis()->GetNbins(); unsigned nbinsY = h->GetYaxis()->GetNbins(); unsigned xMin = 1; unsigned yMin = 1; unsigned xMax = nbinsX; unsigned yMax = nbinsY; unsigned Xbinnum = 1; unsigned Ybinnum = 1; //give users option for automatic mininum and maximum selection by inputting 0 to any of the parameters // check that user's parameters are completely in agreement with histogram // for instance, if inputted xMax is out of range xMin will automatically be ignored if (xMin_ != 0 && xMax_ != 0) { if ((xMax_ <= nbinsX) && (xMin_ <= xMax_)) { nbinsX = xMax_ - xMin_ + 1; xMax = xMax_; // do NOT use overflow bin xMin = xMin_; // do NOT use underflow bin } } if (yMin_ != 0 && yMax_ != 0) { if ((yMax_ <= nbinsY) && (yMin_ <= yMax_)) { nbinsY = yMax_ - yMin_ + 1; yMax = yMax_; yMin = yMin_; } } if (Xblocks == 999) { //Check to see if blocks should be ignored Xblocks = nbinsX; } if (Yblocks == 999) { Yblocks = nbinsY; } Xbinnum = nbinsX / Xblocks; Ybinnum = nbinsY / Yblocks; unsigned xLow, xHi, yLow, yHi; //Define the neighbor blocks edges to be summed if (groupx > neighborsX) { xLow = (groupx - neighborsX) * Xbinnum + xMin; if (xLow < xMin) { xLow = xMin; //If the neigbor block would go outside the histogram edge, set it the edge } } else { xLow = xMin; } xHi = (groupx + 1 + neighborsX) * Xbinnum + xMin; if (xHi > xMax) { xHi = xMax; } if (groupy > neighborsY) { yLow = (groupy - neighborsY) * Ybinnum + yMin; if (yLow < yMin) { yLow = yMin; } } else { yLow = yMin; } yHi = (groupy + 1 + neighborsY) * Ybinnum + yMin; if (yHi > yMax) { yHi = yMax; } for (unsigned xbin = xLow; xbin <= xHi; ++xbin) { //now sum over all the bins for (unsigned ybin = yLow; ybin <= yHi; ++ybin) { sum += h->GetBinContent(xbin, ybin); } } return sum; } //Similar to algorithm above but returns a version of standard deviation. Additional operations to return real standard deviation used above (Chad Freer) double ContentSigma::getNeighborSigma(double average, unsigned groupx, unsigned groupy, unsigned Xblocks, unsigned Yblocks, unsigned neighborsX, unsigned neighborsY, const TH1* h) const { double sigma = 0; unsigned nbinsX = h->GetXaxis()->GetNbins(); unsigned nbinsY = h->GetYaxis()->GetNbins(); unsigned xMin = 1; unsigned yMin = 1; unsigned xMax = nbinsX; unsigned yMax = nbinsY; unsigned Xbinnum = 1; unsigned Ybinnum = 1; double block_sum; if (xMin_ != 0 && xMax_ != 0) { if ((xMax_ <= nbinsX) && (xMin_ <= xMax_)) { nbinsX = xMax_ - xMin_ + 1; xMax = xMax_; xMin = xMin_; } } if (yMin_ != 0 && yMax_ != 0) { if ((yMax_ <= nbinsY) && (yMin_ <= yMax_)) { nbinsY = yMax_ - yMin_ + 1; yMax = yMax_; yMin = yMin_; } } if (Xblocks == 999) { Xblocks = nbinsX; } if (Yblocks == 999) { Yblocks = nbinsY; } Xbinnum = nbinsX / Xblocks; Ybinnum = nbinsY / Yblocks; unsigned xLow, xHi, yLow, yHi; for (unsigned x_block_count = 0; x_block_count <= 2 * neighborsX; ++x_block_count) { for (unsigned y_block_count = 0; y_block_count <= 2 * neighborsY; ++y_block_count) { //Sum over blocks. Need to find standard deviation of average of blocksums. Set up low and hi values similar to sum but for blocks now. if (groupx + x_block_count > neighborsX) { xLow = (groupx + x_block_count - neighborsX) * Xbinnum + xMin; if (xLow < xMin) { xLow = xMin; } } else { xLow = xMin; } xHi = xLow + Xbinnum; if (xHi > xMax) { xHi = xMax; } if (groupy + y_block_count > neighborsY) { yLow = (groupy + y_block_count - neighborsY) * Ybinnum + yMin; if (yLow < yMin) { yLow = yMin; } } else { yLow = yMin; } yHi = yLow + Ybinnum; if (yHi > yMax) { yHi = yMax; } block_sum = 0; for (unsigned x_block_bin = xLow; x_block_bin <= xHi; ++x_block_bin) { for (unsigned y_block_bin = yLow; y_block_bin <= yHi; ++y_block_bin) { block_sum += h->GetBinContent(x_block_bin, y_block_bin); } } sigma += (average - block_sum) * (average - block_sum); //will sqrt and divide by sqrt(N-1) outside of function } } return sigma; } //-----------------------------------------------------------// //---------------- ContentsWithinExpected ---------------------// //-----------------------------------------------------------// // run the test (result: fraction of channels that passed test); // [0, 1] or <0 for failure float ContentsWithinExpected::runTest(const MonitorElement* me) { badChannels_.clear(); if (!me) return -1; if (!me->getRootObject()) return -1; TH1* h = nullptr; //initialize histogram pointer if (verbose_ > 1) std::cout << "QTest:" << getAlgoName() << "::runTest called on " << me->getFullname() << "\n"; int ncx; int ncy; if (useEmptyBins_) { //-- TH2 if (me->kind() == MonitorElement::Kind::TH2F) { ncx = me->getTH2F()->GetXaxis()->GetNbins(); ncy = me->getTH2F()->GetYaxis()->GetNbins(); h = me->getTH2F(); // access Test histo } //-- TH2S else if (me->kind() == MonitorElement::Kind::TH2S) { ncx = me->getTH2S()->GetXaxis()->GetNbins(); ncy = me->getTH2S()->GetYaxis()->GetNbins(); h = me->getTH2S(); // access Test histo } //-- TH2D else if (me->kind() == MonitorElement::Kind::TH2D) { ncx = me->getTH2D()->GetXaxis()->GetNbins(); ncy = me->getTH2D()->GetYaxis()->GetNbins(); h = me->getTH2D(); // access Test histo } //-- TProfile else if (me->kind() == MonitorElement::Kind::TPROFILE) { ncx = me->getTProfile()->GetXaxis()->GetNbins(); ncy = 1; h = me->getTProfile(); // access Test histo } //-- TProfile2D else if (me->kind() == MonitorElement::Kind::TPROFILE2D) { ncx = me->getTProfile2D()->GetXaxis()->GetNbins(); ncy = me->getTProfile2D()->GetYaxis()->GetNbins(); h = me->getTProfile2D(); // access Test histo } else { if (verbose_ > 0) std::cout << "QTest:ContentsWithinExpected" << " ME does not contain TH2F/TH2S/TH2D/TPROFILE/TPROFILE2D, exiting\n"; return -1; } int nsum = 0; double sum = 0.0; double average = 0.0; if (checkMeanTolerance_) { // calculate average value of all bin contents for (int cx = 1; cx <= ncx; ++cx) { for (int cy = 1; cy <= ncy; ++cy) { if (me->kind() == MonitorElement::Kind::TH2F) { sum += h->GetBinContent(h->GetBin(cx, cy)); ++nsum; } else if (me->kind() == MonitorElement::Kind::TH2S) { sum += h->GetBinContent(h->GetBin(cx, cy)); ++nsum; } else if (me->kind() == MonitorElement::Kind::TH2D) { sum += h->GetBinContent(h->GetBin(cx, cy)); ++nsum; } else if (me->kind() == MonitorElement::Kind::TPROFILE) { if (me->getTProfile()->GetBinEntries(h->GetBin(cx)) >= minEntries_ / (ncx)) { sum += h->GetBinContent(h->GetBin(cx)); ++nsum; } } else if (me->kind() == MonitorElement::Kind::TPROFILE2D) { if (me->getTProfile2D()->GetBinEntries(h->GetBin(cx, cy)) >= minEntries_ / (ncx * ncy)) { sum += h->GetBinContent(h->GetBin(cx, cy)); ++nsum; } } } } if (nsum > 0) average = sum / nsum; } // calculate average value of all bin contents int fail = 0; for (int cx = 1; cx <= ncx; ++cx) { for (int cy = 1; cy <= ncy; ++cy) { bool failMean = false; bool failRMS = false; bool failMeanTolerance = false; if (me->kind() == MonitorElement::Kind::TPROFILE && me->getTProfile()->GetBinEntries(h->GetBin(cx)) < minEntries_ / (ncx)) continue; if (me->kind() == MonitorElement::Kind::TPROFILE2D && me->getTProfile2D()->GetBinEntries(h->GetBin(cx, cy)) < minEntries_ / (ncx * ncy)) continue; if (checkMean_) { double mean = h->GetBinContent(h->GetBin(cx, cy)); failMean = (mean < minMean_ || mean > maxMean_); } if (checkRMS_) { double rms = h->GetBinError(h->GetBin(cx, cy)); failRMS = (rms < minRMS_ || rms > maxRMS_); } if (checkMeanTolerance_) { double mean = h->GetBinContent(h->GetBin(cx, cy)); failMeanTolerance = (std::abs(mean - average) > toleranceMean_ * std::abs(average)); } if (failMean || failRMS || failMeanTolerance) { if (me->kind() == MonitorElement::Kind::TH2F) { DQMChannel chan(cx, cy, 0, h->GetBinContent(h->GetBin(cx, cy)), h->GetBinError(h->GetBin(cx, cy))); badChannels_.push_back(chan); } else if (me->kind() == MonitorElement::Kind::TH2S) { DQMChannel chan(cx, cy, 0, h->GetBinContent(h->GetBin(cx, cy)), h->GetBinError(h->GetBin(cx, cy))); badChannels_.push_back(chan); } else if (me->kind() == MonitorElement::Kind::TH2D) { DQMChannel chan(cx, cy, 0, h->GetBinContent(h->GetBin(cx, cy)), h->GetBinError(h->GetBin(cx, cy))); badChannels_.push_back(chan); } else if (me->kind() == MonitorElement::Kind::TPROFILE) { DQMChannel chan( cx, cy, int(me->getTProfile()->GetBinEntries(h->GetBin(cx))), 0, h->GetBinError(h->GetBin(cx))); badChannels_.push_back(chan); } else if (me->kind() == MonitorElement::Kind::TPROFILE2D) { DQMChannel chan(cx, cy, int(me->getTProfile2D()->GetBinEntries(h->GetBin(cx, cy))), h->GetBinContent(h->GetBin(cx, cy)), h->GetBinError(h->GetBin(cx, cy))); badChannels_.push_back(chan); } ++fail; } } } return 1. * (ncx * ncy - fail) / (ncx * ncy); } /// end of normal Test else /// AS quality test !!! { if (me->kind() == MonitorElement::Kind::TH2F) { ncx = me->getTH2F()->GetXaxis()->GetNbins(); ncy = me->getTH2F()->GetYaxis()->GetNbins(); h = me->getTH2F(); // access Test histo } else if (me->kind() == MonitorElement::Kind::TH2S) { ncx = me->getTH2S()->GetXaxis()->GetNbins(); ncy = me->getTH2S()->GetYaxis()->GetNbins(); h = me->getTH2S(); // access Test histo } else if (me->kind() == MonitorElement::Kind::TH2D) { ncx = me->getTH2D()->GetXaxis()->GetNbins(); ncy = me->getTH2D()->GetYaxis()->GetNbins(); h = me->getTH2D(); // access Test histo } else { if (verbose_ > 0) std::cout << "QTest:ContentsWithinExpected AS" << " ME does not contain TH2F/TH2S/TH2D, exiting\n"; return -1; } // if (!rangeInitialized_) return 0; // all accepted if no initialization int fail = 0; for (int cx = 1; cx <= ncx; ++cx) { for (int cy = 1; cy <= ncy; ++cy) { bool failure = false; double Content = h->GetBinContent(h->GetBin(cx, cy)); if (Content) failure = (Content < minMean_ || Content > maxMean_); if (failure) ++fail; } } return 1. * (ncx * ncy - fail) / (ncx * ncy); } /// end of AS quality test } /// set expected value for mean void ContentsWithinExpected::setMeanRange(double xmin, double xmax) { if (xmax < xmin) if (verbose_ > 0) std::cout << "QTest:ContentsWitinExpected" << " Illogical range: (" << xmin << ", " << xmax << "\n"; minMean_ = xmin; maxMean_ = xmax; checkMean_ = true; } /// set expected value for mean void ContentsWithinExpected::setRMSRange(double xmin, double xmax) { if (xmax < xmin) if (verbose_ > 0) std::cout << "QTest:ContentsWitinExpected" << " Illogical range: (" << xmin << ", " << xmax << "\n"; minRMS_ = xmin; maxRMS_ = xmax; checkRMS_ = true; } //----------------------------------------------------------------// //-------------------- MeanWithinExpected ---------------------// //---------------------------------------------------------------// // run the test; // (a) if useRange is called: 1 if mean within allowed range, 0 otherwise // (b) is useRMS or useSigma is called: result is the probability // Prob(chi^2, ndof=1) that the mean of histogram will be deviated by more than // +/- delta from <expected_mean>, where delta = mean - <expected_mean>, and // chi^2 = (delta/sigma)^2. sigma is the RMS of the histogram ("useRMS") or // <expected_sigma> ("useSigma") // e.g. for delta = 1, Prob = 31.7% // for delta = 2, Prob = 4.55% // (returns result in [0, 1] or <0 for failure) float MeanWithinExpected::runTest(const MonitorElement* me) { if (!me) return -1; if (!me->getRootObject()) return -1; TH1* h = nullptr; if (verbose_ > 1) std::cout << "QTest:" << getAlgoName() << "::runTest called on " << me->getFullname() << "\n"; if (minEntries_ != 0 && me->getEntries() < minEntries_) return -1; if (me->kind() == MonitorElement::Kind::TH1F) { h = me->getTH1F(); //access Test histo } else if (me->kind() == MonitorElement::Kind::TH1S) { h = me->getTH1S(); //access Test histo } else if (me->kind() == MonitorElement::Kind::TH1D) { h = me->getTH1D(); //access Test histo } else { if (verbose_ > 0) std::cout << "QTest:MeanWithinExpected" << " ME " << me->getFullname() << " does not contain TH1F/TH1S/TH1D, exiting\n"; return -1; } if (useRange_) { double mean = h->GetMean(); if (mean <= xmax_ && mean >= xmin_) return 1; else return 0; } else if (useSigma_) { if (sigma_ != 0.) { double chi = (h->GetMean() - expMean_) / sigma_; return TMath::Prob(chi * chi, 1); } else { if (verbose_ > 0) std::cout << "QTest:MeanWithinExpected" << " Error, sigma_ is zero, exiting\n"; return 0; } } else if (useRMS_) { if (h->GetRMS() != 0.) { double chi = (h->GetMean() - expMean_) / h->GetRMS(); return TMath::Prob(chi * chi, 1); } else { if (verbose_ > 0) std::cout << "QTest:MeanWithinExpected" << " Error, RMS is zero, exiting\n"; return 0; } } else { if (verbose_ > 0) std::cout << "QTest:MeanWithinExpected" << " Error, neither Range, nor Sigma, nor RMS, exiting\n"; return -1; } } void MeanWithinExpected::useRange(double xmin, double xmax) { useRange_ = true; useSigma_ = useRMS_ = false; xmin_ = xmin; xmax_ = xmax; if (xmin_ > xmax_) if (verbose_ > 0) std::cout << "QTest:MeanWithinExpected" << " Illogical range: (" << xmin_ << ", " << xmax_ << "\n"; } void MeanWithinExpected::useSigma(double expectedSigma) { useSigma_ = true; useRMS_ = useRange_ = false; sigma_ = expectedSigma; if (sigma_ == 0) if (verbose_ > 0) std::cout << "QTest:MeanWithinExpected" << " Expected sigma = " << sigma_ << "\n"; } void MeanWithinExpected::useRMS() { useRMS_ = true; useSigma_ = useRange_ = false; } //----------------------------------------------------------------// //------------------------ CompareToMedian ---------------------------// //----------------------------------------------------------------// /* Test for TProfile2D For each x bin, the median value is calculated and then each value is compared with the median. This procedure is repeated for each x-bin of the 2D profile The parameters used for this comparison are: MinRel and MaxRel to identify outliers wrt the median value An absolute value (MinAbs, MaxAbs) on the median is used to identify a full region out of specification */ float CompareToMedian::runTest(const MonitorElement* me) { int32_t nbins = 0, failed = 0; badChannels_.clear(); if (!me) return -1; if (!me->getRootObject()) return -1; TH1* h = nullptr; if (verbose_ > 1) { std::cout << "QTest:" << getAlgoName() << "::runTest called on " << me->getFullname() << "\n"; std::cout << "\tMin = " << _min << "; Max = " << _max << "\n"; std::cout << "\tMinMedian = " << _minMed << "; MaxMedian = " << _maxMed << "\n"; std::cout << "\tUseEmptyBins = " << (_emptyBins ? "Yes" : "No") << "\n"; } if (me->kind() == MonitorElement::Kind::TPROFILE2D) { h = me->getTProfile2D(); // access Test histo } else { if (verbose_ > 0) std::cout << "QTest:ContentsWithinExpected" << " ME does not contain TPROFILE2D, exiting\n"; return -1; } nBinsX = h->GetNbinsX(); nBinsY = h->GetNbinsY(); int entries = 0; float median = 0.0; //Median calculated with partially sorted vector for (int binX = 1; binX <= nBinsX; binX++) { reset(); // Fill vector for (int binY = 1; binY <= nBinsY; binY++) { int bin = h->GetBin(binX, binY); auto content = (double)h->GetBinContent(bin); if (content == 0 && !_emptyBins) continue; binValues.push_back(content); entries = me->getTProfile2D()->GetBinEntries(bin); } if (binValues.empty()) continue; nbins += binValues.size(); //calculate median if (!binValues.empty()) { int medPos = (int)binValues.size() / 2; nth_element(binValues.begin(), binValues.begin() + medPos, binValues.end()); median = *(binValues.begin() + medPos); } // if median == 0, use the absolute cut if (median == 0) { if (verbose_ > 0) { std::cout << "QTest: Median is 0; the fixed cuts: [" << _minMed << "; " << _maxMed << "] are used\n"; } for (int binY = 1; binY <= nBinsY; binY++) { int bin = h->GetBin(binX, binY); auto content = (double)h->GetBinContent(bin); entries = me->getTProfile2D()->GetBinEntries(bin); if (entries == 0) continue; if (content > _maxMed || content < _minMed) { DQMChannel chan(binX, binY, 0, content, h->GetBinError(bin)); badChannels_.push_back(chan); failed++; } } continue; } //Cut on stat: will mask rings with no enought of statistics if (median * entries < _statCut) continue; // If median is off the absolute cuts, declare everything bad (if bin has non zero entries) if (median > _maxMed || median < _minMed) { for (int binY = 1; binY <= nBinsY; binY++) { int bin = h->GetBin(binX, binY); auto content = (double)h->GetBinContent(bin); entries = me->getTProfile2D()->GetBinEntries(bin); if (entries == 0) continue; DQMChannel chan(binX, binY, 0, content / median, h->GetBinError(bin)); badChannels_.push_back(chan); failed++; } continue; } // Test itself float minCut = median * _min; float maxCut = median * _max; for (int binY = 1; binY <= nBinsY; binY++) { int bin = h->GetBin(binX, binY); auto content = (double)h->GetBinContent(bin); entries = me->getTProfile2D()->GetBinEntries(bin); if (entries == 0) continue; if (content > maxCut || content < minCut) { DQMChannel chan(binX, binY, 0, content / median, h->GetBinError(bin)); badChannels_.push_back(chan); failed++; } } } if (nbins == 0) { if (verbose_ > 0) std::cout << "QTest:CompareToMedian: Histogram is empty" << std::endl; return 1.; } return 1 - (float)failed / nbins; } //----------------------------------------------------------------// //------------------------ CompareLastFilledBin -----------------// //----------------------------------------------------------------// /* Test for TH1F and TH2F For the last filled bin the value is compared with specified upper and lower limits. If it is outside the limit the test failed test result is returned The parameters used for this comparison are: MinRel and MaxRel to check identify outliers wrt the median value */ float CompareLastFilledBin::runTest(const MonitorElement* me) { if (!me) return -1; if (!me->getRootObject()) return -1; TH1* h1 = nullptr; TH2* h2 = nullptr; if (verbose_ > 1) { std::cout << "QTest:" << getAlgoName() << "::runTest called on " << me->getFullname() << "\n"; std::cout << "\tMin = " << _min << "; Max = " << _max << "\n"; } if (me->kind() == MonitorElement::Kind::TH1F) { h1 = me->getTH1F(); // access Test histo } else if (me->kind() == MonitorElement::Kind::TH2F) { h2 = me->getTH2F(); // access Test histo } else { if (verbose_ > 0) std::cout << "QTest:ContentsWithinExpected" << " ME does not contain TH1F or TH2F, exiting\n"; return -1; } int lastBinX = 0; int lastBinY = 0; float lastBinVal; //--------- do the quality test for 1D histo ---------------// if (h1 != nullptr) { lastBinX = h1->FindLastBinAbove(_average, 1); lastBinVal = h1->GetBinContent(lastBinX); if (h1->GetEntries() == 0 || lastBinVal < 0) return 1; } else if (h2 != nullptr) { lastBinX = h2->FindLastBinAbove(_average, 1); lastBinY = h2->FindLastBinAbove(_average, 2); if (h2->GetEntries() == 0 || lastBinX < 0 || lastBinY < 0) return 1; lastBinVal = h2->GetBinContent(h2->GetBin(lastBinX, lastBinY)); } else { if (verbose_ > 0) std::cout << "QTest:" << getAlgoName() << " Histogram does not exist" << std::endl; return 1; } if (verbose_ > 0) std::cout << "Min and Max values " << _min << " " << _max << " Av value " << _average << " lastBinX " << lastBinX << " lastBinY " << lastBinY << " lastBinVal " << lastBinVal << std::endl; if (lastBinVal > _min && lastBinVal <= _max) return 1; else return 0; } //----------------------------------------------------// //--------------- CheckVariance ---------------------// //----------------------------------------------------// float CheckVariance::runTest(const MonitorElement* me) { badChannels_.clear(); if (!me) return -1; if (!me->getRootObject()) return -1; TH1* h = nullptr; if (verbose_ > 1) std::cout << "QTest:" << getAlgoName() << "::runTest called on " << me->getFullname() << "\n"; // -- TH1F if (me->kind() == MonitorElement::Kind::TH1F) { h = me->getTH1F(); } // -- TH1D else if (me->kind() == MonitorElement::Kind::TH1D) { h = me->getTH1D(); } else if (me->kind() == MonitorElement::Kind::TPROFILE) { h = me->getTProfile(); // access Test histo } else { if (verbose_ > 0) std::cout << "QTest:CheckVariance" << " ME " << me->getFullname() << " does not contain TH1F/TH1D/TPROFILE, exiting\n"; return -1; } int ncx = h->GetXaxis()->GetNbins(); double sum = 0; double sum2 = 0; for (int bin = 1; bin <= ncx; ++bin) { double contents = h->GetBinContent(bin); sum += contents; } if (sum == 0) return -1; double avg = sum / ncx; for (int bin = 1; bin <= ncx; ++bin) { double contents = h->GetBinContent(bin); sum2 += (contents - avg) * (contents - avg); } double Variance = TMath::Sqrt(sum2 / ncx); return Variance; }