CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_0/src/DQMServices/Core/src/QTest.cc

Go to the documentation of this file.
00001 #include "DQMServices/Core/interface/QTest.h"
00002 #include "DQMServices/Core/interface/DQMStore.h"
00003 #include "DQMServices/Core/src/QStatisticalTests.h"
00004 #include "DQMServices/Core/src/DQMError.h"
00005 #include "TMath.h"
00006 #include <iostream>
00007 #include <sstream>
00008 #include <math.h>
00009 
00010 using namespace std;
00011 
00012 const float QCriterion::ERROR_PROB_THRESHOLD = 0.50;
00013 const float QCriterion::WARNING_PROB_THRESHOLD = 0.90;
00014 
00015 // initialize values
00016 void
00017 QCriterion::init(void)
00018 {
00019   errorProb_ = ERROR_PROB_THRESHOLD;
00020   warningProb_ = WARNING_PROB_THRESHOLD;
00021   setAlgoName("NO_ALGORITHM");
00022   status_ = dqm::qstatus::DID_NOT_RUN;
00023   message_ = "NO_MESSAGE";
00024   verbose_ = 0; // 0 = silent, 1 = algorithmic failures, 2 = info
00025 }
00026 
00027 float QCriterion::runTest(const MonitorElement * /* me */)
00028 {
00029   raiseDQMError("QCriterion", "virtual runTest method called" );
00030   return 0.;
00031 }
00032 //===================================================//
00033 //================ QUALITY TESTS ====================//
00034 //==================================================//
00035 
00036 //-------------------------------------------------------//
00037 //----------------- Comp2RefEqualH base -----------------//
00038 //-------------------------------------------------------//
00039 // run the test (result: [0, 1] or <0 for failure)
00040 float Comp2RefEqualH::runTest(const MonitorElement*me)
00041 {
00042   badChannels_.clear();
00043 
00044   if (!me) 
00045     return -1;
00046   if (!me->getRootObject() || !me->getRefRootObject()) 
00047     return -1;
00048   TH1* h=0; //initialize histogram pointer
00049   TH1* ref_=0;
00050   
00051   if (verbose_>1) 
00052     std::cout << "QTest:" << getAlgoName() << "::runTest called on " 
00053               << me-> getFullname() << "\n";
00054 
00055   int nbins=0;
00056   int nbinsref=0;
00057   //-- TH1F
00058   if (me->kind()==MonitorElement::DQM_KIND_TH1F)
00059   { 
00060     nbins = me->getTH1F()->GetXaxis()->GetNbins(); 
00061     nbinsref = me->getRefTH1F()->GetXaxis()->GetNbins();
00062     h  = me->getTH1F(); // access Test histo
00063     ref_ = me->getRefTH1F(); //access Ref hiso 
00064     if (nbins != nbinsref) return -1;
00065   } 
00066   //-- TH1S
00067   else if (me->kind()==MonitorElement::DQM_KIND_TH1S)
00068   { 
00069     nbins = me->getTH1S()->GetXaxis()->GetNbins(); 
00070     nbinsref = me->getRefTH1S()->GetXaxis()->GetNbins();
00071     h  = me->getTH1S(); // access Test histo
00072     ref_ = me->getRefTH1S(); //access Ref hiso 
00073     if (nbins != nbinsref) return -1;
00074   } 
00075   //-- TH1D
00076   else if (me->kind()==MonitorElement::DQM_KIND_TH1D)
00077   { 
00078     nbins = me->getTH1D()->GetXaxis()->GetNbins(); 
00079     nbinsref = me->getRefTH1D()->GetXaxis()->GetNbins();
00080     h  = me->getTH1D(); // access Test histo
00081     ref_ = me->getRefTH1D(); //access Ref hiso 
00082     if (nbins != nbinsref) return -1;
00083   } 
00084   //-- TH2
00085   else if (me->kind()==MonitorElement::DQM_KIND_TH2F)
00086   { 
00087     nbins = me->getTH2F()->GetXaxis()->GetNbins() *
00088             me->getTH2F()->GetYaxis()->GetNbins();
00089     nbinsref = me->getRefTH2F()->GetXaxis()->GetNbins() *
00090                me->getRefTH2F()->GetYaxis()->GetNbins();
00091     h = me->getTH2F(); // access Test histo
00092     ref_ = me->getRefTH2F(); //access Ref hiso 
00093     if (nbins != nbinsref) return -1;
00094   } 
00095 
00096   //-- TH2
00097   else if (me->kind()==MonitorElement::DQM_KIND_TH2S)
00098   { 
00099     nbins = me->getTH2S()->GetXaxis()->GetNbins() *
00100             me->getTH2S()->GetYaxis()->GetNbins();
00101     nbinsref = me->getRefTH2S()->GetXaxis()->GetNbins() *
00102                me->getRefTH2S()->GetYaxis()->GetNbins();
00103     h = me->getTH2S(); // access Test histo
00104     ref_ = me->getRefTH2S(); //access Ref hiso 
00105     if (nbins != nbinsref) return -1;
00106   } 
00107 
00108   //-- TH2
00109   else if (me->kind()==MonitorElement::DQM_KIND_TH2D)
00110   { 
00111     nbins = me->getTH2D()->GetXaxis()->GetNbins() *
00112             me->getTH2D()->GetYaxis()->GetNbins();
00113     nbinsref = me->getRefTH2D()->GetXaxis()->GetNbins() *
00114                me->getRefTH2D()->GetYaxis()->GetNbins();
00115     h = me->getTH2D(); // access Test histo
00116     ref_ = me->getRefTH2D(); //access Ref hiso 
00117     if (nbins != nbinsref) return -1;
00118   } 
00119 
00120   //-- TH3
00121   else if (me->kind()==MonitorElement::DQM_KIND_TH3F)
00122   { 
00123     nbins = me->getTH3F()->GetXaxis()->GetNbins() *
00124             me->getTH3F()->GetYaxis()->GetNbins() *
00125             me->getTH3F()->GetZaxis()->GetNbins();
00126     nbinsref = me->getRefTH3F()->GetXaxis()->GetNbins() *
00127                me->getRefTH3F()->GetYaxis()->GetNbins() *
00128                me->getRefTH3F()->GetZaxis()->GetNbins();
00129     h = me->getTH3F(); // access Test histo
00130     ref_ = me->getRefTH3F(); //access Ref hiso 
00131     if (nbins != nbinsref) return -1;
00132   } 
00133 
00134   else
00135   { 
00136     if (verbose_>0) 
00137       std::cout << "QTest:Comp2RefEqualH" 
00138         << " ME does not contain TH1F/TH1S/TH1D/TH2F/TH2S/TH2D/TH3F, exiting\n"; 
00139     return -1;
00140   } 
00141 
00142   //--  QUALITY TEST itself 
00143   int first = 0; // 1 //(use underflow bin)
00144   int last  = nbins+1; //(use overflow bin)
00145   bool failure = false;
00146   for (int bin=first;bin<=last;bin++) 
00147   {
00148     double contents = h->GetBinContent(bin);
00149     if (contents != ref_->GetBinContent(bin)) 
00150     {
00151       failure = true;
00152       DQMChannel chan(bin, 0, 0, contents, h->GetBinError(bin));
00153       badChannels_.push_back(chan);
00154     }
00155   }
00156   if (failure) return 0;
00157   return 1;
00158 }
00159 
00160 //-------------------------------------------------------//
00161 //-----------------  Comp2RefChi2    --------------------//
00162 //-------------------------------------------------------//
00163 float Comp2RefChi2::runTest(const MonitorElement *me)
00164 {
00165   if (!me) 
00166     return -1;
00167   if (!me->getRootObject() || !me->getRefRootObject()) 
00168     return -1;
00169   TH1* h=0;
00170   TH1* ref_=0;
00171  
00172   if (verbose_>1) 
00173     std::cout << "QTest:" << getAlgoName() << "::runTest called on " 
00174               << me-> getFullname() << "\n";
00175   //-- TH1F
00176   if (me->kind()==MonitorElement::DQM_KIND_TH1F)
00177   { 
00178     h = me->getTH1F(); // access Test histo
00179     ref_ = me->getRefTH1F(); //access Ref histo
00180   } 
00181   //-- TH1S
00182   else if (me->kind()==MonitorElement::DQM_KIND_TH1S)
00183   { 
00184     h = me->getTH1S(); // access Test histo
00185     ref_ = me->getRefTH1S(); //access Ref histo
00186   } 
00187   //-- TH1D
00188   else if (me->kind()==MonitorElement::DQM_KIND_TH1D)
00189   { 
00190     h = me->getTH1D(); // access Test histo
00191     ref_ = me->getRefTH1D(); //access Ref histo
00192   } 
00193   //-- TProfile
00194   else if (me->kind()==MonitorElement::DQM_KIND_TPROFILE)
00195   {
00196     h = me->getTProfile(); // access Test histo
00197     ref_ = me->getRefTProfile(); //access Ref histo
00198   } 
00199   else
00200   { 
00201     if (verbose_>0) 
00202       std::cout << "QTest::Comp2RefChi2"
00203                 << " ME does not contain TH1F/TH1S/TH1D/TProfile, exiting\n"; 
00204     return -1;
00205   } 
00206 
00207    //-- isInvalid ? - Check consistency in number of channels
00208   int ncx1  = h->GetXaxis()->GetNbins(); 
00209   int ncx2  = ref_->GetXaxis()->GetNbins();
00210   if ( ncx1 !=  ncx2)
00211   {
00212     if (verbose_>0) 
00213       std::cout << "QTest:Comp2RefChi2"
00214                 << " different number of channels! ("
00215                 << ncx1 << ", " << ncx2 << "), exiting\n";
00216     return -1;
00217   } 
00218 
00219   //--  QUALITY TEST itself 
00220   //reset Results
00221   Ndof_ = 0; chi2_ = -1.; ncx1 = ncx2 = -1;
00222 
00223   int i, i_start, i_end;
00224   double chi2 = 0.;  int ndof = 0; int constraint = 0;
00225 
00226   i_start = 1;  
00227   i_end = ncx1;
00228   //  if (fXaxis.TestBit(TAxis::kAxisRange)) {
00229   i_start = h->GetXaxis()->GetFirst();
00230   i_end   = h->GetXaxis()->GetLast();
00231   //  }
00232   ndof = i_end-i_start+1-constraint;
00233 
00234   //Compute the normalisation factor
00235   double sum1=0, sum2=0;
00236   for (i=i_start; i<=i_end; i++)
00237   {
00238     sum1 += h->GetBinContent(i);
00239     sum2 += ref_->GetBinContent(i);
00240   }
00241 
00242   //check that the histograms are not empty
00243   if (sum1 == 0)
00244   {
00245     if (verbose_>0) 
00246       std::cout << "QTest:Comp2RefChi2"
00247                 << " Test Histogram " << h->GetName() 
00248                 << " is empty, exiting\n";
00249     return -1;
00250   }
00251   if (sum2 == 0)
00252   {
00253     if (verbose_>0) 
00254       std::cout << "QTest:Comp2RefChi2"
00255                 << " Ref Histogram " << ref_->GetName() 
00256                 << " is empty, exiting\n";
00257     return -1;
00258   }
00259 
00260   double bin1, bin2, err1, err2, temp;
00261   for (i=i_start; i<=i_end; i++)
00262   {
00263     bin1 = h->GetBinContent(i)/sum1;
00264     bin2 = ref_->GetBinContent(i)/sum2;
00265     if (bin1 ==0 && bin2==0)
00266     {
00267       --ndof; //no data means one less degree of freedom
00268     } 
00269     else 
00270     {
00271       temp  = bin1-bin2;
00272       err1=h->GetBinError(i); err2=ref_->GetBinError(i);
00273       if (err1 == 0 && err2 == 0)
00274       {
00275         if (verbose_>0) 
00276           std::cout << "QTest:Comp2RefChi2"
00277                     << " bins with non-zero content and zero error, exiting\n";
00278         return -1;
00279       }
00280       err1*=err1      ; err2*=err2;
00281       err1/=sum1*sum1 ; err2/=sum2*sum2;
00282       chi2 +=temp*temp/(err1+err2);
00283     }
00284   }
00285   chi2_ = chi2;  Ndof_ = ndof;
00286   return TMath::Prob(0.5*chi2, int(0.5*ndof));
00287 }
00288 
00289 //-------------------------------------------------------//
00290 //-----------------  Comp2RefKolmogorov    --------------//
00291 //-------------------------------------------------------//
00292 
00293 float Comp2RefKolmogorov::runTest(const MonitorElement *me)
00294 {
00295   const double difprec = 1e-5;
00296    
00297   if (!me) 
00298     return -1;
00299   if (!me->getRootObject() || !me->getRefRootObject()) 
00300     return -1;
00301   TH1* h=0;
00302   TH1* ref_=0;
00303 
00304   if (verbose_>1) 
00305     std::cout << "QTest:" << getAlgoName() << "::runTest called on " 
00306               << me-> getFullname() << "\n";
00307   //-- TH1F
00308   if (me->kind()==MonitorElement::DQM_KIND_TH1F)
00309   { 
00310     h = me->getTH1F(); // access Test histo
00311     ref_ = me->getRefTH1F(); //access Ref histo
00312   } 
00313   //-- TH1S
00314   else if (me->kind()==MonitorElement::DQM_KIND_TH1S)
00315   { 
00316     h = me->getTH1S(); // access Test histo
00317     ref_ = me->getRefTH1S(); //access Ref histo
00318   } 
00319   //-- TH1D
00320   else if (me->kind()==MonitorElement::DQM_KIND_TH1D)
00321   { 
00322     h = me->getTH1D(); // access Test histo
00323     ref_ = me->getRefTH1D(); //access Ref histo
00324   } 
00325   //-- TProfile
00326   else if (me->kind()==MonitorElement::DQM_KIND_TPROFILE)
00327   {
00328     h = me->getTProfile(); // access Test histo
00329     ref_ = me->getRefTProfile(); //access Ref histo
00330   }
00331   else
00332   { 
00333     if (verbose_>0) 
00334       std::cout << "QTest:Comp2RefKolmogorov"
00335                 << " ME does not contain TH1F/TH1S/TH1D/TProfile, exiting\n"; 
00336     return -1;
00337   } 
00338    
00339   //-- isInvalid ? - Check consistency in number of channels
00340   int ncx1 = h->GetXaxis()->GetNbins(); 
00341   int ncx2 = ref_->GetXaxis()->GetNbins();
00342   if ( ncx1 !=  ncx2)
00343   {
00344     if (verbose_>0) 
00345       std::cout << "QTest:Comp2RefKolmogorov"
00346                 << " different number of channels! ("
00347                 << ncx1 << ", " << ncx2 << "), exiting\n";
00348     return -1;
00349   } 
00350   //-- isInvalid ? - Check consistency in channel edges
00351   double diff1 = TMath::Abs(h->GetXaxis()->GetXmin() - ref_->GetXaxis()->GetXmin());
00352   double diff2 = TMath::Abs(h->GetXaxis()->GetXmax() - ref_->GetXaxis()->GetXmax());
00353   if (diff1 > difprec || diff2 > difprec)
00354   {
00355     if (verbose_>0) 
00356       std::cout << "QTest:Comp2RefKolmogorov"
00357                 << " histograms with different binning, exiting\n";
00358     return -1;
00359   }
00360 
00361   //--  QUALITY TEST itself 
00362   Bool_t afunc1 = kFALSE; Bool_t afunc2 = kFALSE;
00363   double sum1 = 0, sum2 = 0;
00364   double ew1, ew2, w1 = 0, w2 = 0;
00365   int bin;
00366   for (bin=1;bin<=ncx1;bin++)
00367   {
00368     sum1 += h->GetBinContent(bin);
00369     sum2 += ref_->GetBinContent(bin);
00370     ew1   = h->GetBinError(bin);
00371     ew2   = ref_->GetBinError(bin);
00372     w1   += ew1*ew1;
00373     w2   += ew2*ew2;
00374   }
00375   
00376   if (sum1 == 0)
00377   {
00378     if (verbose_>0) 
00379       std::cout << "QTest:Comp2RefKolmogorov"
00380                 << " Test Histogram: " << h->GetName() 
00381                 << ": integral is zero, exiting\n";
00382     return -1;
00383   }
00384   if (sum2 == 0)
00385   {
00386     if (verbose_>0) 
00387       std::cout << "QTest:Comp2RefKolmogorov"
00388                 << " Ref Histogram: " << ref_->GetName() 
00389                 << ": integral is zero, exiting\n";
00390     return -1;
00391   }
00392 
00393   double tsum1 = sum1; double tsum2 = sum2;
00394   tsum1 += h->GetBinContent(0);
00395   tsum2 += ref_->GetBinContent(0);
00396   tsum1 += h->GetBinContent(ncx1+1);
00397   tsum2 += ref_->GetBinContent(ncx1+1);
00398 
00399   // Check if histograms are weighted.
00400   // If number of entries = number of channels, probably histograms were
00401   // not filled via Fill(), but via SetBinContent()
00402   double ne1 = h->GetEntries();
00403   double ne2 = ref_->GetEntries();
00404   // look at first histogram
00405   double difsum1 = (ne1-tsum1)/tsum1;
00406   double esum1 = sum1;
00407   if (difsum1 > difprec && int(ne1) != ncx1)
00408   {
00409     if (h->GetSumw2N() == 0)
00410     {
00411       if (verbose_>0) 
00412         std::cout << "QTest:Comp2RefKolmogorov"
00413                   << " Weighted events and no Sumw2 for "
00414                   << h->GetName() << "\n";
00415     }
00416     else
00417     {
00418       esum1 = sum1*sum1/w1;  //number of equivalent entries
00419     }
00420   }
00421   // look at second histogram
00422   double difsum2 = (ne2-tsum2)/tsum2;
00423   double esum2   = sum2;
00424   if (difsum2 > difprec && int(ne2) != ncx1)
00425   {
00426     if (ref_->GetSumw2N() == 0)
00427     {
00428       if (verbose_>0) 
00429         std::cout << "QTest:Comp2RefKolmogorov"
00430                   << " Weighted events and no Sumw2 for "
00431                   << ref_->GetName() << "\n";
00432     }
00433     else
00434     {
00435       esum2 = sum2*sum2/w2;  //number of equivalent entries
00436     }
00437   }
00438 
00439   double s1 = 1/tsum1; double s2 = 1/tsum2;
00440   // Find largest difference for Kolmogorov Test
00441   double dfmax =0, rsum1 = 0, rsum2 = 0;
00442   // use underflow bin
00443   int first = 0; // 1
00444   // use overflow bin
00445   int last  = ncx1+1; // ncx1
00446   for ( bin=first; bin<=last; bin++)
00447   {
00448     rsum1 += s1*h->GetBinContent(bin);
00449     rsum2 += s2*ref_->GetBinContent(bin);
00450     dfmax = TMath::Max(dfmax,TMath::Abs(rsum1-rsum2));
00451   }
00452 
00453   // Get Kolmogorov probability
00454   double z = 0;
00455   if (afunc1)      z = dfmax*TMath::Sqrt(esum2);
00456   else if (afunc2) z = dfmax*TMath::Sqrt(esum1);
00457   else             z = dfmax*TMath::Sqrt(esum1*esum2/(esum1+esum2));
00458 
00459   // This numerical error condition should never occur:
00460   if (TMath::Abs(rsum1-1) > 0.002)
00461     if (verbose_>0) 
00462       std::cout << "QTest:Comp2RefKolmogorov" 
00463                 << " Numerical problems with histogram "
00464                 << h->GetName() << "\n";
00465   if (TMath::Abs(rsum2-1) > 0.002)
00466     if (verbose_>0) 
00467       std::cout << "QTest:Comp2RefKolmogorov" 
00468                 << " Numerical problems with histogram "
00469                 << ref_->GetName() << "\n";
00470 
00471   return TMath::KolmogorovProb(z);
00472 }
00473 
00474 //----------------------------------------------------//
00475 //--------------- ContentsXRange ---------------------//
00476 //----------------------------------------------------//
00477 float ContentsXRange::runTest(const MonitorElement*me)
00478 {
00479   badChannels_.clear();
00480 
00481   if (!me) 
00482     return -1;
00483   if (!me->getRootObject()) 
00484     return -1;
00485   TH1* h=0; 
00486 
00487   if (verbose_>1) 
00488     std::cout << "QTest:" << getAlgoName() << "::runTest called on " 
00489               << me-> getFullname() << "\n";
00490   // -- TH1F
00491   if (me->kind()==MonitorElement::DQM_KIND_TH1F ) 
00492   {
00493     h = me->getTH1F();
00494   } 
00495   // -- TH1S
00496   else if ( me->kind()==MonitorElement::DQM_KIND_TH1S ) 
00497   {
00498     h = me->getTH1S();
00499   } 
00500   // -- TH1D
00501   else if ( me->kind()==MonitorElement::DQM_KIND_TH1D ) 
00502   {
00503     h = me->getTH1D();
00504   } 
00505   else 
00506   {
00507     if (verbose_>0) std::cout << "QTest:ContentsXRange"
00508          << " ME " << me->getFullname() 
00509          << " does not contain TH1F/TH1S/TH1D, exiting\n"; 
00510     return -1;
00511   } 
00512 
00513   if (!rangeInitialized_)
00514   {
00515     if ( h->GetXaxis() ) 
00516       setAllowedXRange(h->GetXaxis()->GetXmin(), h->GetXaxis()->GetXmax());
00517     else 
00518       return -1;
00519   }
00520   int ncx = h->GetXaxis()->GetNbins();
00521   // use underflow bin
00522   int first = 0; // 1
00523   // use overflow bin
00524   int last  = ncx+1; // ncx
00525   // all entries
00526   double sum = 0;
00527   // entries outside X-range
00528   double fail = 0;
00529   int bin;
00530   for (bin = first; bin <= last; ++bin)
00531   {
00532     double contents = h->GetBinContent(bin);
00533     double x = h->GetBinCenter(bin);
00534     sum += contents;
00535     if (x < xmin_ || x > xmax_)fail += contents;
00536   }
00537 
00538   if (sum==0) return 1;
00539   // return fraction of entries within allowed X-range
00540   return (sum - fail)/sum; 
00541 
00542 }
00543 
00544 //-----------------------------------------------------//
00545 //--------------- ContentsYRange ---------------------//
00546 //----------------------------------------------------//
00547 float ContentsYRange::runTest(const MonitorElement*me)
00548 {
00549   badChannels_.clear();
00550 
00551   if (!me) 
00552     return -1;
00553   if (!me->getRootObject()) 
00554     return -1;
00555   TH1* h=0; 
00556 
00557   if (verbose_>1) 
00558     std::cout << "QTest:" << getAlgoName() << "::runTest called on " 
00559               << me-> getFullname() << "\n";
00560 
00561   if (me->kind()==MonitorElement::DQM_KIND_TH1F) 
00562   { 
00563     h = me->getTH1F(); //access Test histo
00564   } 
00565   else if (me->kind()==MonitorElement::DQM_KIND_TH1S) 
00566   { 
00567     h = me->getTH1S(); //access Test histo
00568   } 
00569   else if (me->kind()==MonitorElement::DQM_KIND_TH1D) 
00570   { 
00571     h = me->getTH1D(); //access Test histo
00572   } 
00573   else 
00574   {
00575     if (verbose_>0) 
00576       std::cout << "QTest:ContentsYRange" 
00577                 << " ME " << me->getFullname() 
00578                 << " does not contain TH1F/TH1S/TH1D, exiting\n"; 
00579     return -1;
00580   } 
00581 
00582   if (!rangeInitialized_ || !h->GetXaxis()) return 1; // all bins are accepted if no initialization
00583   int ncx = h->GetXaxis()->GetNbins();
00584   // do NOT use underflow bin
00585   int first = 1;
00586   // do NOT use overflow bin
00587   int last  = ncx;
00588   // bins outside Y-range
00589   int fail = 0;
00590   int bin;
00591   
00592   if (useEmptyBins_)
00593   {
00594     for (bin = first; bin <= last; ++bin)
00595     {
00596       double contents = h->GetBinContent(bin);
00597       bool failure = false;
00598       failure = (contents < ymin_ || contents > ymax_); // allowed y-range: [ymin_, ymax_]
00599       if (failure) 
00600       { 
00601         DQMChannel chan(bin, 0, 0, contents, h->GetBinError(bin));
00602         badChannels_.push_back(chan);
00603         ++fail;
00604       }
00605     }
00606     // return fraction of bins that passed test
00607     return 1.*(ncx - fail)/ncx;
00608   }
00609   else 
00610   {
00611     for (bin = first; bin <= last; ++bin)
00612     {
00613       double contents = h->GetBinContent(bin);
00614       bool failure = false;
00615       if (contents) failure = (contents < ymin_ || contents > ymax_); // allowed y-range: [ymin_, ymax_]
00616       if (failure) ++fail;
00617     }
00618     // return fraction of bins that passed test
00619     return 1.*(ncx - fail)/ncx;
00620   } 
00621 }
00622 
00623 //-----------------------------------------------------//
00624 //------------------ DeadChannel ---------------------//
00625 //----------------------------------------------------//
00626 float DeadChannel::runTest(const MonitorElement*me)
00627 {
00628   badChannels_.clear();
00629   if (!me) 
00630     return -1;
00631   if (!me->getRootObject()) 
00632     return -1;
00633   TH1* h1=0;
00634   TH2* h2=0;//initialize histogram pointers
00635 
00636   if (verbose_>1) 
00637     std::cout << "QTest:" << getAlgoName() << "::runTest called on " 
00638               << me-> getFullname() << "\n";
00639   //TH1F
00640   if (me->kind()==MonitorElement::DQM_KIND_TH1F) 
00641   { 
00642     h1 = me->getTH1F(); //access Test histo
00643   } 
00644   //TH1S
00645   else if (me->kind()==MonitorElement::DQM_KIND_TH1S) 
00646   { 
00647     h1 = me->getTH1S(); //access Test histo
00648   } 
00649   //TH1D
00650   else if (me->kind()==MonitorElement::DQM_KIND_TH1D) 
00651   { 
00652     h1 = me->getTH1D(); //access Test histo
00653   } 
00654   //-- TH2F
00655   else if (me->kind()==MonitorElement::DQM_KIND_TH2F)
00656   { 
00657     h2  = me->getTH2F(); // access Test histo
00658   } 
00659   //-- TH2S
00660   else if (me->kind()==MonitorElement::DQM_KIND_TH2S)
00661   { 
00662     h2  = me->getTH2S(); // access Test histo
00663   } 
00664   //-- TH2D
00665   else if (me->kind()==MonitorElement::DQM_KIND_TH2D)
00666   { 
00667     h2  = me->getTH2D(); // access Test histo
00668   } 
00669   else 
00670   {
00671     if (verbose_>0) 
00672       std::cout << "QTest:DeadChannel"
00673          << " ME " << me->getFullname() 
00674          << " does not contain TH1F/TH1S/TH1D/TH2F/TH2S/TH2D, exiting\n"; 
00675     return -1;
00676   } 
00677 
00678   int fail = 0; // number of failed channels
00679 
00680   //--------- do the quality test for 1D histo ---------------//
00681   if (h1 != NULL)  
00682   {
00683     if (!rangeInitialized_ || !h1->GetXaxis() ) 
00684       return 1; // all bins are accepted if no initialization
00685     int ncx = h1->GetXaxis()->GetNbins();
00686     int first = 1;
00687     int last  = ncx;
00688     int bin;
00689 
00691     for (bin = first; bin <= last; ++bin)
00692     {
00693       double contents = h1->GetBinContent(bin);
00694       bool failure = false;
00695       failure = contents <= ymin_; // dead channel: equal to or less than ymin_
00696       if (failure)
00697       { 
00698         DQMChannel chan(bin, 0, 0, contents, h1->GetBinError(bin));
00699         badChannels_.push_back(chan);
00700         ++fail;
00701       }
00702     }
00703     //return fraction of alive channels
00704     return 1.*(ncx - fail)/ncx;
00705   }
00706   //----------------------------------------------------------//
00707  
00708   //--------- do the quality test for 2D -------------------//
00709   else if (h2 !=NULL )
00710   {
00711     int ncx = h2->GetXaxis()->GetNbins(); // get X bins
00712     int ncy = h2->GetYaxis()->GetNbins(); // get Y bins
00713 
00715     for (int cx = 1; cx <= ncx; ++cx)
00716     {
00717       for (int cy = 1; cy <= ncy; ++cy)
00718       {
00719         double contents = h2->GetBinContent(h2->GetBin(cx, cy));
00720         bool failure = false;
00721         failure = contents <= ymin_; // dead channel: equal to or less than ymin_
00722         if (failure)
00723         { 
00724           DQMChannel chan(cx, cy, 0, contents, h2->GetBinError(h2->GetBin(cx, cy)));
00725           badChannels_.push_back(chan);
00726           ++fail;
00727         }
00728       }
00729     }
00730     //return fraction of alive channels
00731     return 1.*(ncx*ncy - fail) / (ncx*ncy);
00732   }
00733   else 
00734   {
00735     if (verbose_>0) 
00736       std::cout << "QTest:DeadChannel"
00737                 << " TH1/TH2F are NULL, exiting\n"; 
00738     return -1;
00739   }
00740 }
00741 
00742 //-----------------------------------------------------//
00743 //----------------  NoisyChannel ---------------------//
00744 //----------------------------------------------------//
00745 // run the test (result: fraction of channels not appearing noisy or "hot")
00746 // [0, 1] or <0 for failure
00747 float NoisyChannel::runTest(const MonitorElement *me)
00748 {
00749   badChannels_.clear();
00750   if (!me) 
00751     return -1;
00752   if (!me->getRootObject()) 
00753     return -1; 
00754   TH1* h=0;//initialize histogram pointer
00755 
00756   if (verbose_>1) 
00757     std::cout << "QTest:" << getAlgoName() << "::runTest called on " 
00758               << me-> getFullname() << "\n";
00759 
00760   int nbins=0;
00761   //-- TH1F
00762   if (me->kind()==MonitorElement::DQM_KIND_TH1F)
00763   { 
00764     nbins = me->getTH1F()->GetXaxis()->GetNbins(); 
00765     h  = me->getTH1F(); // access Test histo
00766   } 
00767   //-- TH1S
00768   else if (me->kind()==MonitorElement::DQM_KIND_TH1S)
00769   { 
00770     nbins = me->getTH1S()->GetXaxis()->GetNbins(); 
00771     h  = me->getTH1S(); // access Test histo
00772   } 
00773   //-- TH1D
00774   else if (me->kind()==MonitorElement::DQM_KIND_TH1D)
00775   { 
00776     nbins = me->getTH1D()->GetXaxis()->GetNbins(); 
00777     h  = me->getTH1D(); // access Test histo
00778   } 
00779   //-- TH2
00780   else if (me->kind()==MonitorElement::DQM_KIND_TH2F)
00781   { 
00782     nbins = me->getTH2F()->GetXaxis()->GetNbins() *
00783             me->getTH2F()->GetYaxis()->GetNbins();
00784     h  = me->getTH2F(); // access Test histo
00785   } 
00786   //-- TH2
00787   else if (me->kind()==MonitorElement::DQM_KIND_TH2S)
00788   { 
00789     nbins = me->getTH2S()->GetXaxis()->GetNbins() *
00790             me->getTH2S()->GetYaxis()->GetNbins();
00791     h  = me->getTH2S(); // access Test histo
00792   } 
00793   //-- TH2
00794   else if (me->kind()==MonitorElement::DQM_KIND_TH2D)
00795   { 
00796     nbins = me->getTH2D()->GetXaxis()->GetNbins() *
00797             me->getTH2D()->GetYaxis()->GetNbins();
00798     h  = me->getTH2D(); // access Test histo
00799   } 
00800   else 
00801   {  
00802     if (verbose_>0) 
00803       std::cout << "QTest:NoisyChannel"
00804         << " ME " << me->getFullname() 
00805         << " does not contain TH1F/TH1S/TH1D or TH2F/TH2S/TH2D, exiting\n"; 
00806     return -1;
00807   }
00808 
00809   //--  QUALITY TEST itself 
00810 
00811   if ( !rangeInitialized_ || !h->GetXaxis() ) 
00812     return 1; // all channels are accepted if tolerance has not been set
00813 
00814   // do NOT use underflow bin
00815   int first = 1;
00816   // do NOT use overflow bin
00817   int last  = nbins;
00818   // bins outside Y-range
00819   int fail = 0;
00820   int bin;
00821   for (bin = first; bin <= last; ++bin)
00822   {
00823     double contents = h->GetBinContent(bin);
00824     double average = getAverage(bin, h);
00825     bool failure = false;
00826     if (average != 0)
00827        failure = (((contents-average)/TMath::Abs(average)) > tolerance_);
00828 
00829     if (failure)
00830     {
00831       ++fail;
00832       DQMChannel chan(bin, 0, 0, contents, h->GetBinError(bin));
00833       badChannels_.push_back(chan);
00834     }
00835   }
00836 
00837   // return fraction of bins that passed test
00838   return 1.*(nbins - fail)/nbins;
00839 }
00840 
00841 // get average for bin under consideration
00842 // (see description of method setNumNeighbors)
00843 double NoisyChannel::getAverage(int bin, const TH1 *h) const
00844 {
00846   int first = 1;
00848   int ncx  = h->GetXaxis()->GetNbins();
00849   double sum = 0; int bin_low, bin_hi;
00850   for (unsigned i = 1; i <= numNeighbors_; ++i)
00851   {
00853     bin_low = bin-i;  bin_hi = bin+i;
00856     while (bin_low < first) // shift bin by +ncx
00857       bin_low = ncx + bin_low;
00858     while (bin_hi > ncx) // shift bin by -ncx
00859       bin_hi = bin_hi - ncx;
00860       sum += h->GetBinContent(bin_low) + h->GetBinContent(bin_hi);
00861   }
00863   return sum/(numNeighbors_ * 2);
00864 }
00865 
00866 
00867 //-----------------------------------------------------------//
00868 //----------------  ContentsWithinExpected ---------------------//
00869 //-----------------------------------------------------------//
00870 // run the test (result: fraction of channels that passed test);
00871 // [0, 1] or <0 for failure
00872 float ContentsWithinExpected::runTest(const MonitorElement*me)
00873 {
00874   badChannels_.clear();
00875   if (!me) 
00876     return -1;
00877   if (!me->getRootObject()) 
00878     return -1;
00879   TH1* h=0; //initialize histogram pointer
00880 
00881   if (verbose_>1) 
00882     std::cout << "QTest:" << getAlgoName() << "::runTest called on " 
00883               << me-> getFullname() << "\n";
00884 
00885   int ncx;
00886   int ncy;
00887 
00888   if (useEmptyBins_)
00889   {
00890     //-- TH2
00891     if (me->kind()==MonitorElement::DQM_KIND_TH2F)
00892     {
00893       ncx = me->getTH2F()->GetXaxis()->GetNbins();
00894       ncy = me->getTH2F()->GetYaxis()->GetNbins(); 
00895       h  = me->getTH2F(); // access Test histo
00896     }
00897     //-- TH2S
00898     else if (me->kind()==MonitorElement::DQM_KIND_TH2S)
00899     {
00900       ncx = me->getTH2S()->GetXaxis()->GetNbins();
00901       ncy = me->getTH2S()->GetYaxis()->GetNbins(); 
00902       h  = me->getTH2S(); // access Test histo
00903     }
00904     //-- TH2D
00905     else if (me->kind()==MonitorElement::DQM_KIND_TH2D)
00906     {
00907       ncx = me->getTH2D()->GetXaxis()->GetNbins();
00908       ncy = me->getTH2D()->GetYaxis()->GetNbins(); 
00909       h  = me->getTH2D(); // access Test histo
00910     }
00911     //-- TProfile
00912     else if (me->kind()==MonitorElement::DQM_KIND_TPROFILE)
00913     {
00914       ncx = me->getTProfile()->GetXaxis()->GetNbins();
00915       ncy = 1;
00916       h  = me->getTProfile(); // access Test histo
00917     }
00918     //-- TProfile2D
00919     else if (me->kind()==MonitorElement::DQM_KIND_TPROFILE2D)
00920     {
00921       ncx = me->getTProfile2D()->GetXaxis()->GetNbins();
00922       ncy = me->getTProfile2D()->GetYaxis()->GetNbins();
00923       h  = me->getTProfile2D(); // access Test histo
00924     }
00925     else
00926     {
00927       if (verbose_>0) 
00928         std::cout << "QTest:ContentsWithinExpected" 
00929          << " ME does not contain TH2F/TH2S/TH2D/TPROFILE/TPROFILE2D, exiting\n"; 
00930       return -1;
00931     } 
00932 
00933     int nsum = 0;
00934     double sum = 0.0;
00935     double average = 0.0;
00936 
00937     if (checkMeanTolerance_)
00938     { // calculate average value of all bin contents
00939 
00940       for (int cx = 1; cx <= ncx; ++cx)
00941       {
00942         for (int cy = 1; cy <= ncy; ++cy)
00943         {
00944           if (me->kind() == MonitorElement::DQM_KIND_TH2F)
00945           {
00946             sum += h->GetBinContent(h->GetBin(cx, cy));
00947             ++nsum;
00948           }
00949           else if (me->kind() == MonitorElement::DQM_KIND_TH2S)
00950           {
00951             sum += h->GetBinContent(h->GetBin(cx, cy));
00952             ++nsum;
00953           }
00954           else if (me->kind() == MonitorElement::DQM_KIND_TH2D)
00955           {
00956             sum += h->GetBinContent(h->GetBin(cx, cy));
00957             ++nsum;
00958           }
00959           else if (me->kind() == MonitorElement::DQM_KIND_TPROFILE)
00960           {
00961             if (me->getTProfile()->GetBinEntries(h->GetBin(cx)) >= minEntries_/(ncx))
00962             {
00963               sum += h->GetBinContent(h->GetBin(cx));
00964               ++nsum;
00965             }
00966           }
00967           else if (me->kind() == MonitorElement::DQM_KIND_TPROFILE2D)
00968           {
00969             if (me->getTProfile2D()->GetBinEntries(h->GetBin(cx, cy)) >= minEntries_/(ncx*ncy))
00970             {
00971               sum += h->GetBinContent(h->GetBin(cx, cy));
00972               ++nsum;
00973             }
00974           }
00975         }
00976       }
00977 
00978       if (nsum > 0) 
00979         average = sum/nsum;
00980 
00981     } // calculate average value of all bin contents
00982 
00983     int fail = 0;
00984 
00985     for (int cx = 1; cx <= ncx; ++cx)
00986     {
00987       for (int cy = 1; cy <= ncy; ++cy)
00988       {
00989         bool failMean = false;
00990         bool failRMS = false;
00991         bool failMeanTolerance = false;
00992 
00993         if (me->kind() == MonitorElement::DQM_KIND_TPROFILE && 
00994             me->getTProfile()->GetBinEntries(h->GetBin(cx)) < minEntries_/(ncx))
00995           continue;
00996 
00997         if (me->kind() == MonitorElement::DQM_KIND_TPROFILE2D && 
00998             me->getTProfile2D()->GetBinEntries(h->GetBin(cx, cy)) < minEntries_/(ncx*ncy)) 
00999           continue;
01000 
01001         if (checkMean_)
01002         {
01003           double mean = h->GetBinContent(h->GetBin(cx, cy));
01004           failMean = (mean < minMean_ || mean > maxMean_);
01005         }
01006 
01007         if (checkRMS_)
01008         {
01009           double rms = h->GetBinError(h->GetBin(cx, cy));
01010           failRMS = (rms < minRMS_ || rms > maxRMS_);
01011         }
01012 
01013         if (checkMeanTolerance_)
01014         {
01015           double mean = h->GetBinContent(h->GetBin(cx, cy));
01016           failMeanTolerance = (TMath::Abs(mean - average) > toleranceMean_*TMath::Abs(average));
01017         }
01018 
01019         if (failMean || failRMS || failMeanTolerance)
01020         {
01021 
01022           if (me->kind() == MonitorElement::DQM_KIND_TH2F) 
01023           {
01024             DQMChannel chan(cx, cy, 0,
01025                             h->GetBinContent(h->GetBin(cx, cy)),
01026                             h->GetBinError(h->GetBin(cx, cy)));
01027             badChannels_.push_back(chan);
01028           }
01029           else if (me->kind() == MonitorElement::DQM_KIND_TH2S) 
01030           {
01031             DQMChannel chan(cx, cy, 0,
01032                             h->GetBinContent(h->GetBin(cx, cy)),
01033                             h->GetBinError(h->GetBin(cx, cy)));
01034             badChannels_.push_back(chan);
01035           }
01036           else if (me->kind() == MonitorElement::DQM_KIND_TH2D) 
01037           {
01038             DQMChannel chan(cx, cy, 0,
01039                             h->GetBinContent(h->GetBin(cx, cy)),
01040                             h->GetBinError(h->GetBin(cx, cy)));
01041             badChannels_.push_back(chan);
01042           }
01043           else if (me->kind() == MonitorElement::DQM_KIND_TPROFILE) 
01044           {
01045             DQMChannel chan(cx, cy, int(me->getTProfile()->GetBinEntries(h->GetBin(cx))),
01046                             0,
01047                             h->GetBinError(h->GetBin(cx)));
01048             badChannels_.push_back(chan);
01049           }
01050           else if (me->kind() == MonitorElement::DQM_KIND_TPROFILE2D) 
01051           {
01052             DQMChannel chan(cx, cy, int(me->getTProfile2D()->GetBinEntries(h->GetBin(cx, cy))),
01053                             h->GetBinContent(h->GetBin(cx, cy)),
01054                             h->GetBinError(h->GetBin(cx, cy)));
01055             badChannels_.push_back(chan);
01056           }
01057           ++fail;
01058         }
01059       }
01060     }
01061     return 1.*(ncx*ncy - fail)/(ncx*ncy);
01062   } 
01063 
01064   else     
01065   {
01066     if (me->kind()==MonitorElement::DQM_KIND_TH2F)
01067     {
01068       ncx = me->getTH2F()->GetXaxis()->GetNbins();
01069       ncy = me->getTH2F()->GetYaxis()->GetNbins();
01070       h  = me->getTH2F(); // access Test histo
01071     }
01072     else if (me->kind()==MonitorElement::DQM_KIND_TH2S)
01073     {
01074       ncx = me->getTH2S()->GetXaxis()->GetNbins();
01075       ncy = me->getTH2S()->GetYaxis()->GetNbins();
01076       h  = me->getTH2S(); // access Test histo
01077     }
01078     else if (me->kind()==MonitorElement::DQM_KIND_TH2D)
01079     {
01080       ncx = me->getTH2D()->GetXaxis()->GetNbins();
01081       ncy = me->getTH2D()->GetYaxis()->GetNbins();
01082       h  = me->getTH2D(); // access Test histo
01083     }
01084     else 
01085     {
01086       if (verbose_>0) 
01087         std::cout << "QTest:ContentsWithinExpected AS" 
01088                   << " ME does not contain TH2F/TH2S/TH2D, exiting\n"; 
01089       return -1;
01090     } 
01091 
01092     // if (!rangeInitialized_) return 0; // all accepted if no initialization
01093     int fail = 0;
01094     for (int cx = 1; cx <= ncx; ++cx)
01095     {
01096       for (int cy = 1; cy <= ncy; ++cy)
01097       {
01098         bool failure = false;
01099         double Content = h->GetBinContent(h->GetBin(cx, cy));
01100         if (Content) 
01101           failure = (Content <  minMean_ || Content >  maxMean_);
01102         if (failure) 
01103           ++fail;
01104       }
01105     }
01106     return 1.*(ncx*ncy-fail)/(ncx*ncy);
01107   } 
01108 
01109 }
01111 void ContentsWithinExpected::setMeanRange(double xmin, double xmax)
01112 {
01113   if (xmax < xmin)
01114     if (verbose_>0) 
01115       std::cout << "QTest:ContentsWitinExpected" 
01116                 << " Illogical range: (" << xmin << ", " << xmax << "\n";
01117   minMean_ = xmin;
01118   maxMean_ = xmax;
01119   checkMean_ = true;
01120 }
01121 
01123 void ContentsWithinExpected::setRMSRange(double xmin, double xmax)
01124 {
01125   if (xmax < xmin)
01126     if (verbose_>0) 
01127       std::cout << "QTest:ContentsWitinExpected" 
01128                 << " Illogical range: (" << xmin << ", " << xmax << "\n";
01129   minRMS_ = xmin;
01130   maxRMS_ = xmax;
01131   checkRMS_ = true;
01132 }
01133 
01134 //----------------------------------------------------------------//
01135 //--------------------  MeanWithinExpected  ---------------------//
01136 //---------------------------------------------------------------//
01137 // run the test;
01138 //   (a) if useRange is called: 1 if mean within allowed range, 0 otherwise
01139 //   (b) is useRMS or useSigma is called: result is the probability
01140 //   Prob(chi^2, ndof=1) that the mean of histogram will be deviated by more than
01141 //   +/- delta from <expected_mean>, where delta = mean - <expected_mean>, and
01142 //   chi^2 = (delta/sigma)^2. sigma is the RMS of the histogram ("useRMS") or
01143 //   <expected_sigma> ("useSigma")
01144 //   e.g. for delta = 1, Prob = 31.7%
01145 //  for delta = 2, Prob = 4.55%
01146 //   (returns result in [0, 1] or <0 for failure) 
01147 float MeanWithinExpected::runTest(const MonitorElement *me )
01148 {
01149   if (!me) 
01150     return -1;
01151   if (!me->getRootObject()) 
01152     return -1;
01153   TH1* h=0;
01154    
01155   if (verbose_>1) 
01156     std::cout << "QTest:" << getAlgoName() << "::runTest called on " 
01157               << me-> getFullname() << "\n";
01158 
01159   if (minEntries_ != 0 && me->getEntries() < minEntries_) return -1;
01160 
01161   if (me->kind()==MonitorElement::DQM_KIND_TH1F) 
01162   { 
01163     h = me->getTH1F(); //access Test histo
01164   }
01165   else if (me->kind()==MonitorElement::DQM_KIND_TH1S) 
01166   { 
01167     h = me->getTH1S(); //access Test histo
01168   }
01169   else if (me->kind()==MonitorElement::DQM_KIND_TH1D) 
01170   { 
01171     h = me->getTH1D(); //access Test histo
01172   }
01173   else {
01174     if (verbose_>0) 
01175       std::cout << "QTest:MeanWithinExpected"
01176                 << " ME " << me->getFullname() 
01177                 << " does not contain TH1F/TH1S/TH1D, exiting\n"; 
01178     return -1;
01179   } 
01180  
01181   
01182   if (useRange_) {
01183     double mean = h->GetMean();
01184     if (mean <= xmax_ && mean >= xmin_) 
01185       return 1;
01186     else
01187       return 0;
01188   }
01189   else if (useSigma_) 
01190   {
01191     if (sigma_ != 0.) 
01192     {
01193       double chi = (h->GetMean() - expMean_)/sigma_;
01194       return TMath::Prob(chi*chi, 1);
01195     }
01196     else
01197     {
01198       if (verbose_>0) 
01199         std::cout << "QTest:MeanWithinExpected"
01200                   << " Error, sigma_ is zero, exiting\n";
01201       return 0;
01202     }
01203   }
01204   else if (useRMS_) 
01205   {
01206     if (h->GetRMS() != 0.) 
01207     {
01208       double chi = (h->GetMean() - expMean_)/h->GetRMS();
01209       return TMath::Prob(chi*chi, 1);
01210     }
01211     else
01212     {
01213       if (verbose_>0) 
01214         std::cout << "QTest:MeanWithinExpected"
01215                   << " Error, RMS is zero, exiting\n";
01216       return 0;
01217     }
01218   }
01219   else 
01220     if (verbose_>0) 
01221       std::cout << "QTest:MeanWithinExpected"
01222                 << " Error, neither Range, nor Sigma, nor RMS, exiting\n";
01223     return -1; 
01224 }
01225 
01226 void MeanWithinExpected::useRange(double xmin, double xmax)
01227 {
01228     useRange_ = true;
01229     useSigma_ = useRMS_ = false;
01230     xmin_ = xmin; xmax_ = xmax;
01231     if (xmin_ > xmax_)  
01232       if (verbose_>0) 
01233         std::cout << "QTest:MeanWithinExpected"
01234                   << " Illogical range: (" << xmin_ << ", " << xmax_ << "\n";
01235 }
01236 void MeanWithinExpected::useSigma(double expectedSigma)
01237 {
01238   useSigma_ = true;
01239   useRMS_ = useRange_ = false;
01240   sigma_ = expectedSigma;
01241   if (sigma_ == 0) 
01242     if (verbose_>0) 
01243       std::cout << "QTest:MeanWithinExpected"
01244                 << " Expected sigma = " << sigma_ << "\n";
01245 }
01246 
01247 void MeanWithinExpected::useRMS()
01248 {
01249   useRMS_ = true;
01250   useSigma_ = useRange_ = false;
01251 }
01252 
01253 //----------------------------------------------------------------//
01254 //------------------------  CompareToMedian  ---------------------------//
01255 //----------------------------------------------------------------//
01256 /* 
01257 Test for TProfile2D
01258 For each x bin, the median value is calculated and then each value is compared with the median.
01259 This procedure is repeated for each x-bin of the 2D profile
01260 The parameters used for this comparison are:
01261 MinRel and MaxRel to identify outliers wrt the median value
01262 An absolute value (MinAbs, MaxAbs) on the median is used to identify a full region out of specification 
01263 */
01264 float CompareToMedian::runTest(const MonitorElement *me){
01265   int32_t nbins=0, failed=0;
01266   badChannels_.clear();
01267 
01268   if (!me)
01269     return -1;
01270   if (!me->getRootObject())
01271     return -1;
01272   TH1* h=0;
01273 
01274   if (verbose_>1){
01275     std::cout << "QTest:" << getAlgoName() << "::runTest called on "
01276               << me-> getFullname() << "\n";
01277     std::cout << "\tMin = " << _min << "; Max = " << _max << "\n";
01278     std::cout << "\tMinMedian = " << _minMed << "; MaxMedian = " << _maxMed << "\n";
01279     std::cout << "\tUseEmptyBins = " << (_emptyBins?"Yes":"No" )<< "\n";
01280   }
01281 
01282   if (me->kind()==MonitorElement::DQM_KIND_TPROFILE2D)
01283     {
01284       h  = me->getTProfile2D(); // access Test histo
01285     }
01286   else
01287     {
01288       if (verbose_>0) 
01289         std::cout << "QTest:ContentsWithinExpected" 
01290          << " ME does not contain TPROFILE2D, exiting\n"; 
01291       return -1;
01292     }
01293   
01294   nBinsX = h->GetNbinsX();
01295   nBinsY = h->GetNbinsY();
01296   int entries = 0;
01297   float median = 0.0;
01298 
01299   //Median calculated with partially sorted vector
01300   for (int binX = 1; binX <= nBinsX; binX++ ){
01301     reset();
01302     // Fill vector
01303     for (int binY = 1; binY <= nBinsY; binY++){
01304       int bin = h->GetBin(binX, binY);
01305       double content = (double)h->GetBinContent(bin);
01306       if ( content == 0 && !_emptyBins)
01307         continue;
01308       binValues.push_back(content);
01309       entries = me->getTProfile2D()->GetBinEntries(bin);
01310     }
01311     if (binValues.empty())
01312       continue;
01313     nbins+=binValues.size();
01314 
01315     //calculate median
01316     if(binValues.size()>0){
01317       int medPos = (int)binValues.size()/2;
01318       nth_element(binValues.begin(),binValues.begin()+medPos,binValues.end());
01319       median = *(binValues.begin()+medPos);
01320     }
01321 
01322     // if median == 0, use the absolute cut
01323     if(median == 0){
01324       if (verbose_ > 0){
01325         std::cout << "QTest: Median is 0; the fixed cuts: [" << _minMed << "; " << _maxMed << "]  are used\n";
01326       }
01327       for(int  binY = 1; binY <= nBinsY; binY++){
01328         int bin = h->GetBin(binX, binY);
01329         double content = (double)h->GetBinContent(bin);
01330         entries = me->getTProfile2D()->GetBinEntries(bin);
01331         if ( entries == 0 )
01332           continue;
01333         if (content > _maxMed || content < _minMed){ 
01334             DQMChannel chan(binX,binY, 0, content, h->GetBinError(bin));
01335             badChannels_.push_back(chan);
01336             failed++;
01337         }
01338       }
01339       continue;
01340     }
01341 
01342     //Cut on stat: will mask rings with no enought of statistics
01343     if (median*entries < _statCut )
01344       continue;
01345      
01346     // If median is off the absolute cuts, declare everything bad (if bin has non zero entries)
01347     if(median > _maxMed || median < _minMed){
01348       for(int  binY = 1; binY <= nBinsY; binY++){
01349         int bin = h->GetBin(binX, binY);
01350         double content = (double)h->GetBinContent(bin);
01351         entries = me->getTProfile2D()->GetBinEntries(bin);
01352          if ( entries == 0 )
01353           continue;
01354          DQMChannel chan(binX,binY, 0, content/median, h->GetBinError(bin));
01355          badChannels_.push_back(chan);
01356          failed++;
01357       }
01358       continue;
01359     }
01360 
01361     // Test itself  
01362     float minCut = median*_min;
01363     float maxCut = median*_max;
01364     for(int  binY = 1; binY <= nBinsY; binY++){
01365         int bin = h->GetBin(binX, binY);
01366         double content = (double)h->GetBinContent(bin);
01367         entries = me->getTProfile2D()->GetBinEntries(bin);
01368         if ( entries == 0 )
01369           continue;
01370         if (content > maxCut || content < minCut){
01371           DQMChannel chan(binX,binY, 0, content/median, h->GetBinError(bin));
01372           badChannels_.push_back(chan);
01373           failed++;
01374         }
01375     }
01376   }
01377 
01378   if (nbins==0){
01379     if (verbose_ > 0)
01380       std::cout << "QTest:CompareToMedian: Histogram is empty" << std::endl;
01381     return 1.;
01382     }
01383   return 1 - (float)failed/nbins;
01384 }
01385 
01386