RooHistError.cxx

Go to the documentation of this file.
00001 /*****************************************************************************
00002  * Project: RooFit                                                           *
00003  * Package: RooFitCore                                                       *
00004  * @(#)root/roofitcore:$Id: RooHistError.cxx 36222 2010-10-09 18:27:06Z wouter $
00005  * Authors:                                                                  *
00006  *   WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu       *
00007  *   DK, David Kirkby,    UC Irvine,         dkirkby@uci.edu                 *
00008  *                                                                           *
00009  * Copyright (c) 2000-2005, Regents of the University of California          *
00010  *                          and Stanford University. All rights reserved.    *
00011  *                                                                           *
00012  * Redistribution and use in source and binary forms,                        *
00013  * with or without modification, are permitted according to the terms        *
00014  * listed in LICENSE (http://roofit.sourceforge.net/license.txt)             *
00015  *****************************************************************************/
00016 
00017 //////////////////////////////////////////////////////////////////////////////
00018 //
00019 // BEGIN_HTML
00020 // RooHistError is a singleton class used to calculate the error bars
00021 // for each bin of a RooHist object. Errors are calculated by integrating
00022 // a specified area of a Poisson or Binomail error distribution.
00023 // END_HTML
00024 //
00025 
00026 #include "RooFit.h"
00027 
00028 #include "RooHistError.h"
00029 #include "RooBrentRootFinder.h"
00030 #include "RooMsgService.h"
00031 #include "TMath.h"
00032 
00033 #include "Riostream.h"
00034 #include <assert.h>
00035 
00036 ClassImp(RooHistError)
00037   ;
00038 
00039 
00040 
00041 //_____________________________________________________________________________
00042 const RooHistError &RooHistError::instance() 
00043 {
00044   // Return a reference to a singleton object that is created the
00045   // first time this method is called. Only one object will be
00046   // constructed per ROOT session.
00047 
00048   static RooHistError _theInstance;
00049   return _theInstance;
00050 }
00051 
00052 
00053 //_____________________________________________________________________________
00054 RooHistError::RooHistError() 
00055 {
00056   // Construct our singleton object.
00057 
00058   // Initialize lookup table ;
00059   Int_t i ;
00060   for (i=0 ; i<1000 ; i++) {
00061     getPoissonIntervalCalc(i,_poissonLoLUT[i],_poissonHiLUT[i],1.) ;
00062   }
00063 
00064 }
00065 
00066 
00067 
00068 //_____________________________________________________________________________
00069 Bool_t RooHistError::getPoissonInterval(Int_t n, Double_t &mu1, Double_t &mu2, Double_t nSigma) const
00070 {
00071   // Return a confidence interval for the expected number of events given n
00072   // observed (unweighted) events. The interval will contain the same probability
00073   // as nSigma of a Gaussian. Uses a central interval unless this does not enclose
00074   // the point estimate n (ie, for small n) in which case the interval is adjusted
00075   // to start at n. This method uses a lookup table to return precalculated results
00076   // for n<1000
00077 
00078   // Use lookup table for most common cases
00079   if (n<1000 && nSigma==1.) {
00080     mu1=_poissonLoLUT[n] ;
00081     mu2=_poissonHiLUT[n] ;
00082     return kTRUE ;
00083   }
00084 
00085   // Forward to calculation method 
00086   Bool_t ret =  getPoissonIntervalCalc(n,mu1,mu2,nSigma) ;
00087   return ret ;
00088 }
00089 
00090 
00091 
00092 //_____________________________________________________________________________
00093 Bool_t RooHistError::getPoissonIntervalCalc(Int_t n, Double_t &mu1, Double_t &mu2, Double_t nSigma) const
00094 {
00095   // Calculate a confidence interval for the expected number of events given n
00096   // observed (unweighted) events. The interval will contain the same probability
00097   // as nSigma of a Gaussian. Uses a central interval unless this does not enclose
00098   // the point estimate n (ie, for small n) in which case the interval is adjusted
00099   // to start at n.
00100 
00101   // sanity checks
00102   if(n < 0) {
00103     oocoutE((TObject*)0,Plotting) << "RooHistError::getPoissonInterval: cannot calculate interval for n = " << n << endl;
00104     return kFALSE;
00105   }
00106 
00107   // use assymptotic error if possible
00108   if(n > 100) {
00109     mu1= n - sqrt(n+0.25) + 0.5;
00110     mu2= n + sqrt(n+0.25) + 0.5;
00111     return kTRUE;
00112   }
00113 
00114   // create a function object to use
00115   PoissonSum upper(n);
00116   if(n > 0) {
00117     PoissonSum lower(n-1);
00118     return getInterval(&upper,&lower,(Double_t)n,1.0,mu1,mu2,nSigma);
00119   }
00120 
00121   // Backup solution for negative numbers
00122   return getInterval(&upper,0,(Double_t)n,1.0,mu1,mu2,nSigma);
00123 }
00124 
00125 
00126 //_____________________________________________________________________________
00127 Bool_t RooHistError::getBinomialIntervalAsym(Int_t n, Int_t m,
00128                                              Double_t &asym1, Double_t &asym2, Double_t nSigma) const
00129 {
00130   // Return 'nSigma' binomial confidence interval for (n,m). The result is return in asym1 and asym2.
00131   // If the return values is kFALSE and error occurred.
00132 
00133   // sanity checks
00134   if(n < 0 || m < 0) {
00135     oocoutE((TObject*)0,Plotting) << "RooHistError::getPoissonInterval: cannot calculate interval for n,m = " << n << "," << m << endl;
00136     return kFALSE;
00137   }
00138 
00139   // handle the special case of no events in either category
00140   if(n == 0 && m == 0) {
00141     asym1= -1;
00142     asym2= +1;
00143     return kTRUE;
00144   }
00145 
00146   // handle cases when n,m>100 (factorials in BinomialSum will overflow around 170)
00147   if ((n>100&&m>100)) {
00148     Double_t N = n ;
00149     Double_t M = m ;
00150     Double_t asym = 1.0*(N-M)/(N+M) ;
00151     Double_t approxErr = sqrt(4.0*n/(N+M)*(1-N/(N+M))/(N+M)) ;
00152 
00153     asym1 = asym-nSigma*approxErr ;
00154     asym2 = asym+nSigma*approxErr ;
00155     return kTRUE ;
00156   }
00157 
00158   // swap n and m to ensure that n <= m
00159   Bool_t swapped(kFALSE);
00160   if(n > m) {
00161     swapped= kTRUE;
00162     Int_t tmp(m);
00163     m= n;
00164     n= tmp;
00165   }
00166 
00167   // create the function objects to use
00168   Bool_t status(kFALSE);
00169   BinomialSumAsym upper(n,m);
00170   if(n > 0) {
00171     BinomialSumAsym lower(n-1,m+1);
00172     status= getInterval(&upper,&lower,(Double_t)(n-m)/(n+m),0.1,asym1,asym2,nSigma);
00173   }
00174   else {
00175     status= getInterval(&upper,0,(Double_t)(n-m)/(n+m),0.1,asym1,asym2,nSigma);
00176   }
00177 
00178   // undo the swap here
00179   if(swapped) {
00180     Double_t tmp(asym1);
00181     asym1= -asym2;
00182     asym2= -tmp;
00183   }
00184 
00185   return status;
00186 }
00187 
00188 
00189 //_____________________________________________________________________________
00190 Bool_t RooHistError::getBinomialIntervalEff(Int_t n, Int_t m,
00191                                              Double_t &asym1, Double_t &asym2, Double_t nSigma) const
00192 {
00193   // Return 'nSigma' binomial confidence interval for (n,m). The result is return in asym1 and asym2.
00194   // If the return values is kFALSE and error occurred.
00195 
00196   // sanity checks
00197   if(n < 0 || m < 0) {
00198     oocoutE((TObject*)0,Plotting) << "RooHistError::getPoissonInterval: cannot calculate interval for n,m = " << n << "," << m << endl;
00199     return kFALSE;
00200   }
00201 
00202   // handle the special case of no events in either category
00203   if(n == 0 && m == 0) {
00204     asym1= -1;
00205     asym2= +1;
00206     return kTRUE;
00207   }
00208 
00209   // handle cases when n,m>80 (factorials in BinomialSum will overflow around 170)
00210   if ((n>80&&m>80)) {
00211     Double_t N = n ;
00212     Double_t M = m ;
00213     Double_t asym = 1.0*(N)/(N+M) ;
00214     Double_t approxErr = sqrt(4.0*n/(N+M)*(1-N/(N+M))/(N+M)) ;
00215 
00216     asym1 = asym-nSigma*approxErr ;
00217     asym2 = asym+nSigma*approxErr ;
00218     return kTRUE ;
00219   }
00220 
00221   // swap n and m to ensure that n <= m
00222   Bool_t swapped(kFALSE);
00223   if(n > m) {
00224     swapped= kTRUE;
00225     Int_t tmp(m);
00226     m= n;
00227     n= tmp;
00228   }
00229 
00230   // create the function objects to use
00231   Bool_t status(kFALSE);
00232   BinomialSumEff upper(n,m);
00233   Double_t eff = (Double_t)(n)/(n+m) ;
00234   if(n > 0) {
00235     BinomialSumEff lower(n-1,m+1);
00236     status= getInterval(&upper,&lower,eff,0.1,asym1,asym2,nSigma);
00237   }
00238   else {
00239     status= getInterval(&upper,0,eff,0.1,asym1,asym2,nSigma);
00240   }
00241 
00242   // undo the swap here
00243   if(swapped) {
00244     Double_t tmp(asym1);
00245     asym1= 1-asym2;
00246     asym2= 1-tmp;
00247   }
00248 
00249   return status;
00250 }
00251 
00252 
00253 
00254 //_____________________________________________________________________________
00255 Bool_t RooHistError::getInterval(const RooAbsFunc *Qu, const RooAbsFunc *Ql, Double_t pointEstimate,
00256                                  Double_t stepSize, Double_t &lo, Double_t &hi, Double_t nSigma) const
00257 {
00258   // Calculate a confidence interval using the cumulative functions provided.
00259   // The interval will be "central" when both cumulative functions are provided,
00260   // unless this would exclude the pointEstimate, in which case a one-sided interval
00261   // pinned at the point estimate is returned instead.
00262 
00263   // sanity checks
00264   assert(0 != Qu || 0 != Ql);
00265 
00266   // convert number of sigma into a confidence level
00267   Double_t beta= TMath::Erf(nSigma/sqrt(2.));
00268   Double_t alpha= 0.5*(1-beta);
00269 
00270   // Does the central interval contain the point estimate?
00271   Bool_t ok(kTRUE);
00272   Double_t loProb(1),hiProb(0);
00273   if(0 != Ql) loProb= (*Ql)(&pointEstimate);
00274   if(0 != Qu) hiProb= (*Qu)(&pointEstimate);
00275 
00276   if (Qu && (0 == Ql || loProb > alpha + beta))  {
00277     // Force the low edge to be at the pointEstimate
00278     lo= pointEstimate;
00279     Double_t target= loProb - beta;
00280     hi= seek(*Qu,lo,+stepSize,target);
00281     RooBrentRootFinder uFinder(*Qu);
00282     ok= uFinder.findRoot(hi,hi-stepSize,hi,target);
00283   }
00284   else if(Ql && (0 == Qu || hiProb < alpha)) {
00285     // Force the high edge to be at pointEstimate
00286     hi= pointEstimate;
00287     Double_t target= hiProb + beta;
00288     lo= seek(*Ql,hi,-stepSize,target);
00289     RooBrentRootFinder lFinder(*Ql);
00290     ok= lFinder.findRoot(lo,lo,lo+stepSize,target);
00291   }
00292   else if (Qu && Ql) {
00293     // use a central interval
00294     lo= seek(*Ql,pointEstimate,-stepSize,alpha+beta);
00295     hi= seek(*Qu,pointEstimate,+stepSize,alpha);
00296     RooBrentRootFinder lFinder(*Ql),uFinder(*Qu);
00297     ok= lFinder.findRoot(lo,lo,lo+stepSize,alpha+beta);
00298     ok|= uFinder.findRoot(hi,hi-stepSize,hi,alpha);
00299   }
00300   if(!ok) oocoutE((TObject*)0,Plotting) << "RooHistError::getInterval: failed to find root(s)" << endl;
00301 
00302   return ok;
00303 }
00304 
00305 
00306 //_____________________________________________________________________________
00307 Double_t RooHistError::seek(const RooAbsFunc &f, Double_t startAt, Double_t step, Double_t value) const 
00308 {
00309   // Scan f(x)-value until it changes sign. Start at the specified point and take constant
00310   // steps of the specified size. Give up after 1000 steps.
00311   
00312   Int_t steps(1000);
00313   Double_t min(f.getMinLimit(1)),max(f.getMaxLimit(1));
00314   Double_t x(startAt), f0= f(&startAt) - value;
00315   do {
00316     x+= step;
00317   }
00318   while(steps-- && (f0*(f(&x)-value) >= 0) && ((x-min)*(max-x) >= 0));
00319   assert(0 != steps);
00320   if(x < min) x= min;
00321   if(x > max) x= max;
00322 
00323   return x;
00324 }
00325 
00326 
00327 
00328 //_____________________________________________________________________________
00329 RooAbsFunc *RooHistError::createPoissonSum(Int_t n) 
00330 { 
00331   // Create and return a PoissonSum function binding
00332 
00333   return new PoissonSum(n); 
00334 }
00335 
00336 
00337 //_____________________________________________________________________________
00338 RooAbsFunc *RooHistError::createBinomialSum(Int_t n, Int_t m, Bool_t eff) 
00339 { 
00340   // Create and return a BinomialSum function binding
00341   if (eff) {
00342     return new BinomialSumEff(n,m) ;
00343   } else {
00344     return new BinomialSumAsym(n,m) ;
00345   }
00346 }

Generated on Tue Jul 5 15:06:42 2011 for ROOT_528-00b_version by  doxygen 1.5.1